假设我有一个包含一些字段的Person
记录:
data Person = Person
{ name :: String
, age :: Int
, id :: Int
}
我希望能够按给定字段搜索Person
列表:
findByName :: String -> [Person] -> Maybe Person
findByName s = find (\p -> name p == s)
现在,假设我希望能够将这些搜索/查询建模并存储为数据,例如用于日志记录目的,或者批处理执行它们,等等。
如何将对给定字段(或字段集)的搜索表示为数据?
我的直觉告诉我应该将其建模为字段到字符串值的Map(Map (RecordField) (Maybe String)
),但我不能这样做,因为记录字段是函数。
有没有比下面更好的方法呢?
data PersonField = Name | Age | Int
type Search = Map PersonField (Maybe String)
这在技术上是可行的,但它以一种丑陋的方式将PersonField
与Person
分离。
2条答案
按热度按时间shstlldc1#
我希望能够将这些搜索/查询建模并存储为数据
假设我们希望将它们存储为JSON。
其中
storePredicate
将返回 predicate 中“引用值”的JSON表示形式。例如,“age equals 77”的值为77。对于每条记录,我们希望有一个如下所示的集合:
也就是说:对于每个字段,我们可以提供一个JSON值,对 predicate 的“reference value”进行编码,如果解析成功,则得到
Predicate
,否则得到Nothing
。这将允许我们对 predicate 进行序列化和反序列化。我们可以为每条记录手动定义
FieldPredicates
,但有没有更自动化的方法呢?我们可以尝试使用类型类生成字段相等 predicate 。但首先,扩展和导入会跳舞:现在我们定义helper类型类:
以
Person
为例:让它发挥作用:
fjaof16o2#
如果不需要将这些查询对象序列化到磁盘上,那么您的“字段”类型就是
Person -> a
。记录访问器只是从Person
到某种类型a
的函数。或者,如果您最终无法使用基本访问器,需要处理大量嵌套数据,那么您可以考虑lenses。但是,听起来您希望能够将这些查询写入磁盘。在这种情况下,您不能轻松地序列化函数(或镜头,就这一点而言)。我不知道Haskell内置的方法可以自动完成所有这些操作,同时仍然使其可序列化。因此,我的建议是滚动您自己的数据类型。
或者更好的是,可以使用GADTs来保持类型安全。
我认为
Map PersonField (Maybe String)
是一个很好的开始,如果您最终要执行更复杂的查询(例如,“contains”或“不区分大小写的比较”),您可以对Maybe String
部分进行细化。