Haskell 转换镜头';a b进入透镜';a(也许b)
我有几个数据结构,比如Haskell 转换镜头';a b进入透镜';a(也许b),haskell,lenses,haskell-lens,Haskell,Lenses,Haskell Lens,我有几个数据结构,比如 data Data1=Data1 {u data1Field::Int --更多领域 }推导(等式,显示) 生成“数据1” 数据Data2=Data2 {u data2Field::Int --更多领域 }推导(等式,显示) 生成数据2 --更相似的数据类型 因此,我决定编写一个简单的类型类,使其更易于编写 类HasField a,其中 字段::镜头“a Int” 实例HasField Data1,其中 字段=数据1字段 实例HasField Data2,其中 字段=数
data Data1=Data1
{u data1Field::Int
--更多领域
}推导(等式,显示)
生成“数据1”
数据Data2=Data2
{u data2Field::Int
--更多领域
}推导(等式,显示)
生成数据2
--更相似的数据类型
因此,我决定编写一个简单的类型类,使其更易于编写
类HasField a,其中
字段::镜头“a Int”
实例HasField Data1,其中
字段=数据1字段
实例HasField Data2,其中
字段=数据2字段
但后来我遇到了一个问题,其中一些结构将相应的字段作为可选字段
data Data3=Data3
{u data3Field::可能是Int
--更多领域
}推导(等式,显示)
生成数据3
现在我不能再使用type类了。由于有大约相同数量的数据类型具有可选字段,因此我决定最好更改typeclass:
类HasField a,其中
字段::镜头“a”(可能是Int)
实例HasField Data3,其中
字段=数据3字段
但由于我对镜头库不是很有经验,我一直在想如何使这种新镜头与Data1
和Data2
的类型配合使用。理想情况下,我希望能够查看它并获得任何类型的Maybe Int
值,当设置时,我希望Just x
将Data1
和Data2
的字段设置为x
,并且在传递Nothing
时,这两种类型都不可操作
这是可能的使用现有的组合或我将不得不写自己的镜头?我很乐意这样做,但是现有的大多数教程都使用TH,并对手工编写的细节进行了润色
我使用GHC 7.6.3和
lens
3.10.作为shachaf的后续版本
class HasFieldA d where
field :: Traversal' d Int
instance HasFieldA Data1 where
field = data1Field -- Lens's are Traversals
instance HasFieldA Data3 where
field = data3Field . _Just
然后是^?
运算符或^..
运算符
getField :: HasFieldA d => d -> Maybe Int
getField = d ^? field -- or preview field d
去拿
要设置可选字段,需要另一个函数
class SetFieldA d where
setField :: Setter' d Int
instance SetFieldA Data3 where
setField = set data3Field . Just
你根本不能这么做,因为这是非法镜头。镜头法则:
view l(set l x s)=x
,因此,如果将其设置为Nothing
,则在查看时必须获得Nothing
。但这可能是您实际上想要一个遍历
(这类似于镜头对0个或多个值的遍历,而不仅仅是一个值)。当您有一个遍历
时,您可以使用预览
来查看可能
和设置
来设置。@shachaf我该如何为此编写遍历
?此外,如果这些记录有多个这样的字段,会不会有问题?@shachaf或者,有什么好的阅读材料可以帮助我理解如何编写这些类型的遍历s?这不允许将“无”字段值更改为“仅”字段值though@bennofs这是正确的。这使我可以为Data1
和Data2
设置字段,但不能为Data3
@bennofs@bheklillr设置字段,如果我们这样做,我们就会违反遍历的规则。如果我们设置了一个Nothing
字段,那么后续的遍历会受到影响,那么我们需要保留与开始时相同数量的目标。@jozefg那么有没有办法仍然满足镜头定律,并有一个易于使用的组合器,可以同时对这两种情况都起作用?还是我只是走错了路,试图让镜头做不该做的事?@bheklillr我想你是的。我现在就用这个,看看你在哪里