我有几个数据结构,比如
data Data1 = Data1
{ _data1Field :: Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data1
data Data2 = Data2
{ _data2Field :: Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data2
-- More similar data types
所以我决定编写一个简单的类型类,以便更容易编写
class HasField a where
field :: Lens' a Int
instance HasField Data1 where
field = data1Field
instance HasField Data2 where
field = data2Field
然后我遇到了一些问题,其中一些结构具有相应的字段作为可选
data Data3 = Data3
{ _data3Field :: Maybe Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data3
现在我不能再使用类型了。由于大约有相同数量的数据类型具有该字段可选,因此我认为更改类型类更好:
class HasField a where
field :: Lens' a (Maybe Int)
instance HasField Data3 where
field = data3Field
但由于我对镜头库不是很有经验,所以我很难弄清楚如何让这个新镜头与Data1
和Data2
的类型配合使用。理想情况下,我希望能够查看它并为任何类型获取Maybe Int
值,并且在设置时我希望Just x
将字段设置为x
Data1
1}}和Data2
并且在传递Nothing
时成为这两种类型的无操作。
这可能是使用现有的组合器还是我自己必须写镜头?我很好,但是现有的大多数教程都使用了TH,并且对手工编写的细节有所了解。
我正在使用GHC 7.6.3和lens
3.10。
答案 0 :(得分:2)
作为沙夫的后续行动
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