Haskell,Lenses,Getters和Setters

时间:2013-12-17 05:54:47

标签: haskell lens

我无法理解Haskell中镜头库的所有细微差别。

假设我有以下镜头

activePlayer :: Lens' Game Player
activePlayer = lens get set
    where
        get (Game {_players = (index, seq) }) = S.index seq index
        set g@(Game {_players = (index, seq) }) player =
            g { _players = (index, S.update index player seq) }

在ghci提示符下执行以下操作没有问题:

> :t do{use (activePlayer); activePlayer.= undefined}
     :: Control.Monad.State.Class.MonadState Game m => m ()

然而,当我尝试将其参数化为函数时,我得到以下错误。

> :t \p -> do{use p; p.=undefined}
<interactive>:1:17:
    Couldn't match type `Accessor a0 a0' with `Mutator b0'
    Expected type: ASetter s0 s0 a0 b0
      Actual type: Getting a0 s0 a0
    In the first argument of `(.=)', namely `p'
    In a stmt of a 'do' block: p .= undefined
    In the expression:
      do { use p;
           p .= undefined }

当我希望将p推断为完整Accessor时,Lens被推断为p。我尝试强制Lens成为Lens' a b,但是ghci抱怨:t \p -> do{use p; p.=undefined} :: Lens' a b -> m c 中的RankNTypes。

p

如果有人能帮助我弄清楚为什么Lens被推断出来,以及我如何使其表现为一个完整的{{1}},我将不胜感激。

1 个答案:

答案 0 :(得分:26)

发生了什么事?

发生这种情况的原因是,如果你看一下Lens'的类型:

type Lens' s a = forall f. Functor f => (a -> f a) -> s -> f s

这实际上是让您能够在任何一个Functor Lens'中选择f进行交易。但是,use想要选择Accessor a,而.=想要选择Mutator

如何做你的要求

如果您传递Lens并希望多次使用不同的仿函数选项,则需要

a。)以更高级别的类型传递它

 {-# LANGUAGE RankNTypes #-}

 foo :: MonadState a m => Lens' a b -> m ()
 foo p = do 
   use p
   p .= undefined

b。)cloneLens在您使用它进行阅读和/或写作之前。

:t \p -> do{use (cloneLens p); cloneLens p.=undefined}

每侧使用cloneLens可以选择Functor,每次都会生成一个新的镜头。

c。)使用Control.Lens.Loupe中的组合子。

:t \p -> do gets (^# p); p #= undefined

这些设计旨在始终与cloneLens做出相同的选择。

如何做你可能想要的事情

在实践中,最好使用其他方法,例如

:t \p -> p %= \oldValue -> newValue

因为这会支持所有TraversalSetter,而不只是Lens,为您提供更多用例。

如果您需要获取该值以供将来计算:

:t \p -> p %%= \oldValue -> (whatYouWantToReadFromIt, whatYouWantToWriteToIt)