Control.Lens镜头为总地图

npo*_*cop 5 haskell lenses haskell-lens

我有一个从A类到B类的总映射.

import qualified Data.Map as M
import Data.Maybe

tmGet k m = fromJust $ M.lookup k m

tmSet k v = M.insert k v
Run Code Online (Sandbox Code Playgroud)

我用它Data.Map作为一个示例实现,但它可以是任何东西,例如一个Array甚至是一个Bool索引的元组:

tmGet True  = fst
tmGet False = snd
Run Code Online (Sandbox Code Playgroud)

我想要一个tmAt构建镜头的功能:

(42, 665) ^. tmAt True == 42
(42, 665) & tmAt False +~ 1 == (42, 666)
Run Code Online (Sandbox Code Playgroud)

现在的问题是我如何建构tmAt出来tmGettmSet(或tmModify)?

kqr*_*kqr 3

如果您查看Control.Lens 模块的文档,就会发现镜头包不同部分的非常方便的图像。既然你想构造一个Lens,你可以看一下Lens图的部分。显示的最上面的函数是

\n\n
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b\n
Run Code Online (Sandbox Code Playgroud)\n\n

这从 getter 和 setter 构造了一个 Lens。

\n\n

该函数s -> a是一个 getter \xe2\x80\x93 类型签名的意思是,“如果你给我一个数据结构s,我会a从中选择一个值。” 该s -> b -> t函数是 setter,类型签名的意思是,“如果你给我一个s新值b,我将为你创建一个新结构t。” (类型不同,因为镜头实际上可以改变事物的类型。)

\n\n

如果你的 getter 是tmGet并且你的 setter 是tmSet,那么你可以用

\n\n
tmAt :: Boolean -> Lens s t a b\ntmAt b = lens (tmGet b) (tmSet b)\n
Run Code Online (Sandbox Code Playgroud)\n\n

无论您的实际stab参数是什么。在元组的示例中,它将是

\n\n
tmAt :: Bool -> Lens (a, a) (a, a) a a\n
Run Code Online (Sandbox Code Playgroud)\n\n

(换句话说,如果你给 Lens 一个函数a -> a,它可以将一个(a, a)-tuple 转换为另一个(a, a)-tuple。)

\n\n
\n\n

如果你想花哨一点,也可以重写tmAt

\n\n
tmAt = lens <$> tmGet <*> tmSet\n
Run Code Online (Sandbox Code Playgroud)\n