Haskell 中关系数据的安全建模

2024-03-24

我发现在函数式程序中对关系数据建模是很常见的。例如,在开发网站时,我可能希望使用以下数据结构来存储有关我的用户的信息:

data User = User 
  { name :: String
  , birthDate :: Date
  }

接下来,我想存储有关用户在我的网站上发布的消息的数据:

data Message = Message
  { user :: User
  , timestamp :: Date
  , content :: String
  }

这种数据结构存在多个问题:

  • 我们没有任何方法来区分具有相似姓名和出生日期的用户。
  • 用户数据将在序列化/反序列化时重复
  • 比较用户需要比较他们的数据,这可能是一项成本高昂的操作。
  • 更新以下字段User很脆弱——你可能会忘记更新所有出现的User在你的数据结构中。

当您的数据可以表示为树时,这些问题是可以管理的。例如,您可以这样重构:

data User = User
  { name :: String
  , birthDate :: Date
  , messages :: [(String, Date)] -- you get the idea
  }

但是,可以将数据塑造为 DAG(想象任何多对多关系),甚至是一般图形(好吧,也许不是)。在这种情况下,我倾向于通过将数据存储在中来模拟关系数据库Maps:

newtype Id a = Id Integer
type Table a = Map (Id a) a

这种方法可行,但由于多种原因不安全且丑陋:

  • 你只是一个Id构造函数调用远离无意义的查找。
  • 查找时你会得到Maybe a,但通常数据库在结构上确保有一个值。
  • 这很笨拙。
  • 很难确保数据的引用完整性。
  • 管理索引(这对于性能来说非常必要)并确保其完整性更加困难和笨拙。

是否有现有的工作来克服这些问题?

看起来 Template Haskell 可以解决它们(就像通常那样),但我不想重新发明轮子。


The ixset http://hackage.haskell.org/package/ixset图书馆(或ixset-typed https://hackage.haskell.org/package/ixset-typed-0.5/docs/Data-IxSet-Typed.html,一个更类型安全的版本)将帮助您解决这个问题。它是支持关系部分的库acid-state http://hackage.haskell.org/package/acid-state,如果您需要的话,它还可以处理数据的版本化序列化和/或并发保证。

Happstack 书有一个IxSet 教程 http://happstack.com/docs/crashcourse/index.html#ixset-a-set-with-multiple-indexed-keys.


事情是关于ixset是它自动管理您的数据条目的“密钥”。

对于您的示例,人们将为您的数据类型创建一对多关系,如下所示:

data User =
  User
  { name :: String
  , birthDate :: Date
  } deriving (Ord, Typeable)

data Message =
  Message
  { user :: User
  , timestamp :: Date
  , content :: String
  } deriving (Ord, Typeable)

instance Indexable Message where
  empty = ixSet [ ixGen (Proxy :: Proxy User) ]

然后您可以找到特定用户的消息。如果您已经建立了一个IxSet像这样:

user1 = User "John Doe" undefined
user2 = User "John Smith" undefined

messageSet =
  foldr insert empty
  [ Message user1 undefined "bla"
  , Message user2 undefined "blu"
  ]

...然后您可以通过以下方式查找消息user1 with:

user1Messages = toList $ messageSet @= user1

如果您需要查找消息的用户,只需使用user功能正常。这模拟了一对多关系。

现在,对于多对多关系,情况如下:

data User =
  User
  { name :: String
  , birthDate :: Date
  , messages :: [Message]
  } deriving (Ord, Typeable)

data Message =
  Message
  { users :: [User]
  , timestamp :: Date
  , content :: String
  } deriving (Ord, Typeable)

...您创建一个索引ixFun,可与索引列表一起使用。就像这样:

instance Indexable Message where
  empty = ixSet [ ixFun users ]

instance Indexable User where
  empty = ixSet [ ixFun messages ]

要查找用户的所有消息,您仍然使用相同的函数:

user1Messages = toList $ messageSet @= user1

此外,假设您有用户索引:

userSet =
  foldr insert empty
  [ User "John Doe" undefined [ messageFoo, messageBar ]
  , User "John Smith" undefined [ messageBar ]
  ]

...您可以找到一条消息的所有用户:

messageFooUsers = toList $ userSet @= messageFoo

如果您不想在添加新用户/消息时更新消息的用户或用户的消息,则应该创建一个中间数据类型来对用户和消息之间的关系进行建模,就像在 SQL 中一样(并删除users and messages字段):

data UserMessage = UserMessage { umUser :: User, umMessage :: Message } 

instance Indexable UserMessage where
  empty = ixSet [ ixGen (Proxy :: Proxy User), ixGen (Proxy :: Proxy Message) ]

创建一组这些关系将允许您通过消息和用户消息查询用户,而无需更新任何内容。

考虑到它的功能,该库的界面非常简单!

EDIT:关于您的“需要比较的昂贵数据”:ixset仅比较您在索引中指定的字段(因此,要在第一个示例中查找用户的所有消息,它会比较“整个用户”)。

您可以通过更改来调节它比较索引字段的哪些部分Ord实例。因此,如果比较用户对您来说成本高昂,您可以添加userId字段并修改instance Ord User例如,仅比较该字段。

这也可以用来解决先有鸡还是先有蛋的问题:如果你有一个 id,但没有一个,怎么办?User, nor a Message?

然后,您可以简单地为 id 创建一个显式索引,通过该 id 查找用户(使用userSet @= (12423 :: Id)),然后进行搜索。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Haskell 中关系数据的安全建模 的相关文章

  • 在 Haskell 中计算移动平均线

    我正在学习 Haskell 所以我尝试实现移动平均函数 这是我的代码 mAverage Int gt Int gt Float mAverage x a fromIntegral k fromIntegral x k lt rawAvera
  • Haskell 类型系统的细微差别

    我一直在深入了解 haskell 类型系统的本质 并试图了解类型类的要点 我已经学到了很多东西 但我在下面的代码片段上遇到了困难 使用这些类和实例定义 class Show a gt C a where f Int gt a instanc
  • Haskell:是的,没有类型类。为什么是整数?

    我有一个关于 GHCi 如何假定整数类型的问题 我正在阅读 Learn you a Haskell 是 否类型的课程 如果您想阅读全文 这里有一个链接 http learnyouahaskell com making our own typ
  • 如何在 Haskell 中向右或向左移动列表的 1 个元素?

    嗨 我一直在寻找答案 但找不到 假设我们有一个像这样的列表 1 10 4 5 3 我怎样才能将 5 向左移动 使这个列表变成 1 10 5 4 3 我尝试过了swapElementsAt通过找到该元素的索引 但它看起来非常不足 swapEl
  • 搜索重写规则

    有什么办法可以浏览或搜索重写规则吗 当我使用像这样的标志时 ddump rule firings or ddump rule rewrites我只是得到了触发的规则的名称以及它引起的重写 但没有得到实际的规则本身 理想情况下 我想通过 GH
  • 在依赖类型的函数式编程语言中,扁平化列表是否更容易?

    在 haskell 中寻找一个可以展平任意深度嵌套列表的函数时 即应用的函数concat递归并在最后一次迭代时停止 使用非嵌套列表 我注意到这需要有一个更灵活的类型系统 因为随着列表深度的变化 输入类型也会变化 确实 有几个 stackov
  • 在关系数据库中存储树结构的已知方法有哪些? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 规范化且不可变的数据模型

    Haskell如何解决 规范化不可变数据结构 问题 例如 让我们考虑一个表示前女友 男友的数据结构 data Man Man name String exes Woman data Woman Woman name String exes
  • “Eta减少”并不总是在Haskell中举行?

    我发现我可以说 LANGUAGE RankNTypes f1 forall b b gt b gt forall c c gt c f1 f id f HLint 告诉我我可以在这里做 Eta 减少 但是 f2 forall b b gt
  • 使用 FoldLine 解析多个块

    对于这个简化的问题 我试图解析一个如下所示的输入 foo bar baz quux woo hoo xyzzy glulx into foo bar baz quux woo hoo xyzzy glulx 我尝试过的代码如下 import
  • 为什么Redis中没有有序的hashmap?

    Redis 数据类型 http redis io topics data types包括排序集 http redis io topics data types intro sorted sets以及其他用于键值存储的必要数据结构 但我想知道
  • 如何在 Haskell 中制作打勾游戏的图案?

    实现有 2 个参数的函数 ticktick 第一个参数是自然数元组 定义游戏场地的行数和列数 第二个列表包含由玩家 x 和玩家 o 轮流玩的坐标给出的井字游戏比赛的记录 打印游戏的实际状态 其中游戏区域将由字符 和 界定 空方块 以及字符
  • 找不到模块“Yesod”

    我有以下代码 LANGUAGE TypeFamilies QuasiQuotes MultiParamTypeClasses TemplateHaskell OverloadedStrings module Simple where imp
  • Haskell 输入返回元组

    我想知道 IO 函数是否可以返回元组 因为我想从这个函数中获取这些元组作为另一个函数的输入 investinput IO gt Char Int investinput do putStrLn Enter Username username
  • 软删除与数据库存档

    建议阅读 相似的 软删除是个好主意吗 https stackoverflow com q 2549839 1026459 好文章 http weblogs asp net fbouma archive 2009 02 19 soft del
  • Data.Sequence 中的 inits 和 tails 如何工作?

    Louis Wasserman 编写了当前的实现inits and tails in Data Sequence 他表示它们非常高效 事实上 只要查看代码 我就可以看到 无论它们在做什么 它们都是以干净 自上而下的方式进行的 这往往会给惰性
  • 检查对以下内容的理解:“变量”与“变量” “价值”、“功能”与“抽象”

    这个问题是后续问题this one https stackoverflow com questions 25327705 is function a sort of variable 25329157 25329157在学习 Haskell
  • 如何在Haskell中实现词法分析器和解析器

    我在这里得到了这段代码 它是用Haskell结构的命令式编程语言编写的程序 所以问题是 我如何为这种语言实现词法分析器和解析器 该程序被定义为一系列语句有 6 种类型 goto write stop if goto 和 int int n
  • 我是否需要采取明确的操作来促进与持久数据结构的共享?

    我来自命令式背景 正在尝试实现一个简单的不相交集 并集查找 数据结构 以获得在 Haskell 中创建和修改 持久 数据结构的一些练习 目标是有一个简单的实现 但我也关心效率 我的问题与此相关 首先 我创建了一个按等级并集的不相交集森林实现
  • 关于“没有绑定的类型签名”的错误

    我在 Haskell 中遇到 ASCII 问题 fromEnum Char gt Int toEnum Int gt Char offset Int offset fromEnum A fromEnum a toUpper Char gt

随机推荐

  • 如何在matlab中将向量添加到矩阵?

    如何将向量添加到 Matlab 中的矩阵中 以将向量的 i 索引添加到 i 行中的所有成员的方式 例如 A 1 2 3 4 5 6 6 7 8 v 1 2 3 所需的结果是 2 3 4 6 7 8 9 10 11 多谢 您可以使用bsxfu
  • 求大数阶乘​​的快速方法

    这是我的程序 但是对于像 100 000 这样的大数字 它的运行速度非常慢 有什么选项可以优化吗 import java math BigInteger import java util Scanner public class Main
  • python分块三对角矩阵

    我想从三个 numpy ndarray 开始创建一个块三对角矩阵 有没有任何 直接 方法可以在 python 中做到这一点 先感谢您 Cheers 对于 常规 numpy 数组 使用numpy diag http docs scipy or
  • 如何在 for_each 中组合函数和谓词?

    你怎么能打电话给Function over some容器的一部分 使用for each 我创建了一个for each if 做一个 for i in shapes if i color 1 displayShape i 电话看起来像 for
  • 用于挂钩进程函数的 Linux 模块

    我有一个问题 也许你有一些关于这方面的信息 我想在运行进程中挂钩套接字接收函数 recv 并修改传入数据 我怎么知道 我可以使用内核模块来做到这一点 但我找不到有关如何执行此类挂钩的信息 我尝试过其他方法 例如 Netfilter ipta
  • 使用 Alamofire ObjectMapper 映射到 Swift 对象问题显示 nil

    我是 iOS 和 Swift 开发环境的新手 我试图使用 Alamofire 来提取 JSON 并使用 AlamofireObjectMapper 将检索到的 JSON 集合映射回我的 Swift 对象 问题是我可以通过 Alamofire
  • Calendar.getTime() 失败,并显示 java.lang.IllegalArgumentException:MINUTE(对于亚洲/新加坡时区)

    为什么这段代码会失败 目的是删除时间部分 String dateStr 1982 01 01 String timeZoneID Asia Singapore DateFormat dateFormat new SimpleDateForm
  • django图像上传表单

    我在 django 表单和图像上传方面遇到问题 我已经用谷歌搜索 阅读了文档 甚至还提出了问题 但无法找出问题所在 这是我的文件 我的模特 class UserProfile User user with app settings DESI
  • 以编程方式 IIS 6.0 - 创建虚拟目录且未将其设置为应用程序时出现问题

    因此 我以编程方式在 IIS 6 0 中创建虚拟目录 但我遵循有关创建虚拟目录的唯一 MSDN 或其他 文档 但我的文档位于 http msdn microsoft com en us library ms525598 VS 90 aspx
  • 从范围引用但未定义的 LambdaExpression 变量

    我有一个简单的 lambda 表达式 我想编译和调用它 Expression lt Func lt Commands bool gt gt expression c gt c IsValid test 但是当我执行以下操作时 LambdaE
  • 变异下标越界

    我正在尝试从两个插入符号模型输出创建敏感性和特异性的汇总表 并且在我的 for 循环中 当从包含值的名为 models 的列表中查找值时 它会抛出下标越界错误 这是一个完全可重现的示例 Dplyr 的版本是 0 7 0 谢谢 heart l
  • Laravel、AngularJS 和 CORS 的路由问题

    我一直在广泛寻找解决这个问题的方法 我有一个 AngularJS Web 应用程序 其后端实现为 Laravel 4 如下所示 http app mydomain io AngularJS web app http api mydomain
  • 在 x86 32 位中禁用分页

    我试图直接写入物理内存位置 因此我使用汇编函数首先禁用分页 写入值 然后重新启用分页 但由于某种原因 在尝试写入时仍然会触发页面错误价值 据我了解 在x86 32位中 通过翻转cr0中的第32位来打开和关闭分页 所以这是我的汇编函数 mov
  • 使用 robocopy 复制文件(长名称和路径,以及许多空格) - 缺少参数

    我尝试使用 robocopy 复制文件 但 PowerShell 给出错误 MissingArgument robocopy D Enciclopedia mia Tutorial FATTI DA ME Internet Google L
  • 是否可以让您上传的 iPhone 应用程序自动更新? [复制]

    这个问题在这里已经有答案了 我即将将我的 iPhone 应用程序上传到苹果商店 但我打算在不久的将来发布更多版本 一旦我将新版本上传到苹果商店 是否有办法使我的应用程序自动更新 也就是说 我即将上传版本 1 0 一旦我上传版本 1 x 用户
  • 并发字典 AddOrUpdate 与索引添加

    在当前项目中 我可以通过两种方式为并发字典中的现有键分配值 A concurrentDictionary1 key value and B concurrentDictionary2 AddOrUpdate key value k v gt
  • 如何在 Pygame 中获取显示器的分辨率?

    我只是想知道我是否可以在 Pygame 中获取显示器的分辨率 然后使用这些尺寸创建一个窗口 以便启动程序检测显示器分辨率 然后自动将窗口适合全屏屏幕 我目前正在使用pygame display set mode AN INTEGER AN
  • weblogic.jndi.WLInitialContextFactory 类在哪里?

    当尝试执行我的 jar 文件时 出现异常 javax naming NoInitialContextException Cannot instantiate class weblogic jndi WLInitialContextFacto
  • 有条件地将操作添加到 Java 8 流

    我想知道是否可以根据流外部设置的某种条件向流添加操作 例如 我想向流添加限制操作 如果我的limit变量不等于 1 我的代码目前看起来像这样 但我还没有看到以这种方式使用流的其他示例 其中 Stream 对象被重新分配给应用于自身的中间操作
  • Haskell 中关系数据的安全建模

    我发现在函数式程序中对关系数据建模是很常见的 例如 在开发网站时 我可能希望使用以下数据结构来存储有关我的用户的信息 data User User name String birthDate Date 接下来 我想存储有关用户在我的网站上发