如何使用Lens在嵌套Map中设置值

时间:2016-04-23 19:39:52

标签: haskell dictionary lens

我有以下程序:

{-# LANGUAGE TemplateHaskell #-}
import qualified Data.Map.Strict as Map
import Control.Lens

data MyLabel = MyLabel { _label :: String } deriving (Show, Eq, Ord)
data MyMap = MyMap { _vals :: Map.Map String MyLabel } deriving (Show, Eq, Ord)
makeLenses ''MyLabel
makeLenses ''MyMap

sample :: MyMap
sample = MyMap { _vals = Map.fromList [("foo", MyLabel "bar")] }

现在我想知道如何使用镜头进行转换f

f sample "quux" == MyMap { _vals = Map.fromList [("foo", MyLabel "quux")] }

我了解到Lens库中的函数at应该用来修改地图,所以我试图做这样的事情:

sample ^. vals & at "foo" . label .~ Just "quux"

但这会产生一条错误信息,对我来说这是不可理解的。这样做的正确方法是什么?

2 个答案:

答案 0 :(得分:5)

尝试使用此尺寸:

{-# LANGUAGE TemplateHaskell #-}

module Main where

import qualified Data.Map.Strict as Map
import Control.Lens

data MyLabel =
  MyLabel { _label :: String } deriving (Show, Eq, Ord)

data MyMap =
  MyMap { _vals :: Map.Map String MyLabel } deriving (Show, Eq, Ord)

makeLenses ''MyLabel
makeLenses ''MyMap

sample :: MyMap
sample =
  MyMap (Map.fromList [("foo", MyLabel "bar")])

main :: IO ()
main =
  print (sample & (vals . at "foo" . _Just . label .~ "quux"))

请记住,在设置时,您正在尝试构建类型为MyMap -> MyMap的函数。你这样做的方法是将一堆光学器件链接在一起(vals . at "foo" . _Just . label),然后选择一个setter操作(.~)。您不能将^.之类的getter操作与.~之类的setter操作混合搭配!所以每个二传手都或多或少看起来像这样:

foo' = (optic1 . optic2 . optic3 . optic4) .~ value $ foo
--     _________this has type Foo -> Foo___________

为了提高可读性,我们使用& $的翻转版本:

foo' = foo & (optic1 . optic2 . optic3 . optic4) .~ value

答案 1 :(得分:-1)

问题实际上是由阴谋集团地狱造成的,清理~/.ghc目录是必要的,以使其发挥作用。