Haskell镜头:让Traversal'

时间:2015-06-09 07:23:49

标签: haskell traversal lens

我有点困惑,不知道在哪里寻找以下信息/解释"问题" (这本身不是问题,但更多的是我不了解幕后的问题):

我有一个带 StateT 的monad变换器堆栈。在我的函数中的某个时刻,我想将我的一小部分状态绑定到局部变量中,所以我可以引用它而不是写出我感兴趣的状态块的整个路径。这是我的意思是:

find()

现在没有编译:

{-# LANGUAGE ScopedTypeVariables #-}

...

someFunction :: MyMonad ()
someFunction = do
  ...
  let x :: Traversal' MyState MyDataT = myState.clients.ix clientIdx.someData.ix dataIdx
  ...

但是如果我将这个数据块的引用移动到一个函数中,那么一切都可以编译好:

Couldn't match type ‘(MyDataT -> f0 MyDataT)
                     -> MyState -> f0 MyState’
              with ‘forall (f :: * -> *).
                    Control.Applicative.Applicative f =>
                    (MyDataT -> f MyDataT) -> MyState -> f MyState’

我正在寻找某种信息,这些信息可以帮助我了解这里发生了什么,为什么会发生这种情况,以便我了解自己做错了什么。基本上我想扩展我的知识,以便更好地理解这个用例。

1 个答案:

答案 0 :(得分:6)

这里的关键点是注释应该在一个单独的行中。如果我们这样做,那么就GHC而言,我们有一个明确类型的绑定。

someFunction :: MyMonad ()
someFunction = do
  ...
  let x :: Traversal' MyState MyDataT 
      x = myState.clients.ix clientIdx.someData.ix dataIdx
  ...

您最初尝试的内容很少按预期工作:

let x :: Traversal' MyState MyDataT = ...

这是一个没有显式类型的绑定;注释在左侧是里面。 GHC在查看右侧之前考虑固定变量的类型,但是注释仅适用于左侧,因此GHC只是分别为右侧有一个类型,然后尝试将其与注释完全匹配。除了最简单的非多态情况之外,这使得类型检查失败。

将注释放在绑定中的正确方法如下:

let x = ... :: Traversal' MyState MyDataT

在这里,GHC首先将一个“可塑的”不确定类型变量分配给x,然后通过那里的注释推断右侧的类型,然后将x的类型统一到其中。

这仍然是一个没有显式类型的绑定,但如果我们启用NoMonomorphismRestriction,它会正常工作,原因在于此SO question