ram*_*ion 20 haskell haskell-lens
鉴于类型
data Prisoner = P { _name :: String
, _rank :: Int
, _cereal :: Cereal }
data Cereal = C { _number :: Int
, _percentDailyValue :: Map String Float
, _mascot :: String }
Run Code Online (Sandbox Code Playgroud)
我可以通过模式匹配来提取某人的姓名,等级和谷物数量:
getNameRankAndCerealNumber_0 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_0 (P { _name=name
, _rank=rank
, _cereal = C { _number=cerealNumber }}
) = (name, rank, cerealNumber)
Run Code Online (Sandbox Code Playgroud)
或者,我可以使用镜头分别提取每个部分
makeLenses ''Cereal
makeLenses ''Prisoner
getNameRankAndCerealNumber_1 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_1 p = (p ^. name, p ^. rank, p ^. cereal.number)
Run Code Online (Sandbox Code Playgroud)
有没有办法在数据结构的单次遍历中同时提取所有三个?
结合Getters的一些方法,Getter s a -> Getter s b -> Getter s (a,b)?
dan*_*iaz 22
我们可以使用newtype 的Applicative实例:ReifiedGetterControl.Lens.Reified
runGetter $ (,) <$> Getter number <*> Getter mascot
Run Code Online (Sandbox Code Playgroud)
一般来说,newtypes Control.Lens.Reified为getter和folds提供了许多非常有用的实例.
注意#1:请注意,我们将镜片组合为吸气剂,并获得吸气剂作为回报.你不能以这种方式获得复合镜头,因为如果它们的"焦点"重叠会有问题.在这种情况下,什么可能是适当的setter行为?
注意#2:旁边功能可让您将两个镜头组合在一起,获得一个可以在产品的两半上工作的真正镜头.这与前一种情况不同,因为我们可以确定镜头不重叠.alongside当你的类型是元组或者与元组具有同构时,它会派上用场.
充实danidiaz的回答以上,我能够在构建Getter Prisoner (String, Int, Int)使用ReifiedGetter:
getNameRankAndCerealNumber_2 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_2 = p ^. nameRankAndCerealNumber_2
nameRankAndCerealNumber_2 :: Getter Prisoner (String, Int, Int)
nameRankAndCerealNumber_2 = runGetter ((,,) <$> Getter name <*> Getter rank <*> Getter (cereal.number))
Run Code Online (Sandbox Code Playgroud)
和Lens' Prisoner (String, Int, Int)使用alongside,但我不得不手动构建Iso's之间Prisoner和HList [String, Int, Int]之间HList [a,b,c]和(a,b,c).
getNameRankAndCerealNumber_3 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_3 p = p ^. nameRankAndCerealNumber_3
setNameRankAndCerealNumber_3 :: (String, Int, Int) -> Prisoner -> Prisoner
setNameRankAndCerealNumber_3 t p = p & nameRankAndCerealNumber_3 .~ t
nameRankAndCerealNumber_3 :: Lens' Prisoner (String, Int, Int)
nameRankAndCerealNumber_3 = hlist . alongside id (alongside id number) . triple
where triple :: Iso' (a,(b,c)) (a,b,c)
triple = dimap (\(a,(b,c)) -> (a,b,c)) (fmap $ \(a,b,c) -> (a,(b,c)))
hlist :: Iso' Prisoner (String, (Int, Cereal))
hlist = dimap (\(P n r c) -> (n,(r,c))) (fmap $ \(n,(r,c)) -> P n r c)
Run Code Online (Sandbox Code Playgroud)
可能有一种更简单的方法可以做到这一点,但这是另一个问题.