12

我无法理解 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被推断为. 我尝试强制使用以下内容,但 ghci 抱怨 RankNTypes in 。AccessorLenspLensLens' a b

:t \p -> do{use p; p.=undefined} :: Lens' a b -> m c

如果有人能帮助我弄清楚为什么p会以这种方式推断出来,以及如何使它表现得像一个完整的Lens.

4

1 回答 1

28

怎么了?

发生这种情况的原因是,如果您查看以下类型Lens'

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

这本质上是让您能够以您想要Lens'的任何一种 Functor 选择进行交易f。不过,use想摘Accessor a.=又想摘Mutator

怎么做你问的

如果你通过了 aLens并且想要多次使用它并选择不同的函子,你需要要么

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

因为这将支持任何Traversalor Setter,而不仅仅是 a Lens,从而为您打开更多用例。

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

:t \p -> p %%= \oldValue -> (whatYouWantToReadFromIt, whatYouWantToWriteToIt)
于 2013-12-17T07:12:46.807 回答