我有一张从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我使用Data.Map作为示例实现,但它可以是任何东西,例如Array甚至Bool-indexed元组:
tmGet True = fst
tmGet False = snd我希望有一个tmAt函数来构造一个透镜:
(42, 665) ^. tmAt True == 42
(42, 665) & tmAt False +~ 1 == (42, 666)问题是如何用tmGet和tmSet (或tmModify)构建tmGet?
发布于 2013-10-15 13:16:08
如果你看Control.Lens模块的文档,有一个非常方便的图像,不同的部分的镜头包。因为您想要构造一个Lens,所以可以查看图的Lens部分。显示的最上面的函数是
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b这将从一个吸气器和一个策划者构造一个透镜。
函数s -> a是一个getter --类型签名的意思是,“如果您给我一个数据结构s,我将从中选择一个a值。”s -> b -> t函数是setter,类型签名的意思是:“如果您给我一个s和一个新的值b,我将为您创建一个新的结构t。”(类型不同,因为镜片实际上可以改变事物的类型。)
如果您的getter是tmGet,而setter是tmSet,那么您可以用
tmAt :: Boolean -> Lens s t a b
tmAt b = lens (tmGet b) (tmSet b)无论您的实际s、t、a和b参数是什么。在元组的例子中,它应该是
tmAt :: Bool -> Lens (a, a) (a, a) a a(换句话说,如果您给透镜一个函数a -> a,它可以将一个(a, a)-tuple转换成另一个(a, a)-tuple。)
如果您想要花哨,也可以将tmAt重写为
tmAt = lens <$> tmGet <*> tmSet发布于 2013-10-15 13:12:28
一旦您将tmGet和tmSet定义为类型
tmGet :: k -> f v -> v
tmSet :: k -> f v -> v -> f v您可以通过使用参数化的getter和setter来给透镜构造函数lens定义一系列透镜。下面是如何为Bool索引的一对
tmGet True = fst
tmGet False = snd
tmSet True (_,b) a = (a,b)
tmSet False (a,_) b = (a,b)
tmAt b = lens (tmGet b) (tmSet b)现在在GHCI
>>> (42,665) ^. tmAt True
42
>>> (42,665) & tmAt False +~ 1
(42,666)https://stackoverflow.com/questions/19381552
复制相似问题