1

尝试编译某些镜头代码时遇到类型错误。

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens.Setter (over)
import Control.Lens.Getter (view)
import Control.Lens.TH

data IL = IL {
  _ilL :: [Int]
}
  deriving (Show)

makeLenses ''IL

val = IL [1, 2, 3]

(val1, val2) = let l = ilL
       in  (over l tail val, view l val)

错误是:

Test.hs:17:35:
    Couldn't match expected type `Control.Lens.Internal.Getter.Accessor [Int] [Int]'
                with actual type `Control.Lens.Internal.Setter.Mutator [Int]'
    Expected type: Control.Lens.Getter.Getting [Int] s0 [Int]
      Actual type: ([Int]
                    -> Control.Lens.Internal.Setter.Mutator [Int])
                   -> IL -> Control.Lens.Internal.Setter.Mutator IL
    In the first argument of `view', namely `l'
    In the expression: view l val

如果我直接使用 ilL,这个错误就会消失。但是,我确实需要使用 let 进行镜头定义。我该如何解决这个问题?

4

1 回答 1

2

又一个可怕的单态限制的例子。{-# LANGUAGE NoMonormorphismRestriction #-}在文件顶部添加,它会编译得很好。

原因是当您let l = ilL in ...没有显式类型签名(或禁用 MR)时,GHC 希望l尽可能多地专门化类型。它首先遇到它的用途over l tail val并专门用于那里需要的类型,但这与 .in 中的专门推断类型冲突view l val。解决方案是禁用 MR 或添加显式类型签名,如

(val1, val2) =
    let l :: Lens' IL [Int]
        l = ilL
    in  (over l tail val, view l val)

这与更简单的情况非常相似,例如

x = let y = 1
        z = 2 :: Int
        w = 3 :: Double
    in (z + y, w + y)

类型应该y是什么?对于 MR,编译器希望将类型限制为y单一类型,但我们真的希望它具有类型Num a => a,因为这可以与Ints 或Doubles 一起使用。关闭 MR 后,编译器不会专门化类型,y并且一切都按预期工作。另一种方法是给出y一个显式的类型签名,但是当我们可以让编译器为我们做这件事时,为什么所有这些都可以工作呢?

于 2015-04-23T14:06:32.340 回答