将镜头'a b转换为镜头'a(也许b)

时间:2013-11-04 16:08:12

标签: haskell lenses lens

我有几个数据结构,比如

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

但由于我对镜头库不是很有经验,所以我很难弄清楚如何让这个新镜头与Data1Data2的类型配合使用。理想情况下,我希望能够查看它并为任何类型获取Maybe Int值,并且在设置时我希望Just x将字段设置为x Data1 1}}和Data2并且在传递Nothing时成为这两种类型的无操作。

这可能是使用现有的组合器还是我自己必须写镜头?我很好,但是现有的大多数教程都使用了TH,并且对手工编写的细节有所了解。

我正在使用GHC 7.6.3和lens 3.10。

1 个答案:

答案 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