1

I am encountering a type error when trying to compile some lens code.

{-# 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)

The error is:

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

This error goes away if I use ilL directly. However, I really need to make a lens definition using let. How can I solve this?

user3458168
  • 97
  • 1
  • 4
  • 5
    Are you OK with me closing this question as a duplicate of [this](http://stackoverflow.com/a/7055932/1651941) post? A couple of us here on SO are trying to alleviate the problem of so many questions whose answer is "Turn off the DMR". It's not your fault, this question is really hard to find the answer for on Google without prior knowledge of the DMR. That's why we're trying to link as many questions together as possible with one canonical answer, we're trying to funnel a large number of seemingly different questions towards the same answer so others can find it easier in the future. – bheklilr Apr 23 '15 at 14:25

1 Answers1

2

Yet another case of the dreaded monomorphism restriction. Add {-# LANGUAGE NoMonormorphismRestriction #-} at the top of your file and it will compile just fine.

The reason is because when you do let l = ilL in ... without an explicit type signature (or the MR disabled) GHC wants to specialize the type of l as much as it can. It first encounters its use in over l tail val and specializes to the type needed there, but this conflicts with the specialized inferred type in view l val. The solution is to disable the MR or add explicit type signatures like

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

This is very similar to a more simple case like

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

What should the type of y be? With the MR the compiler wants to restrict the type of y to be a single type, but we would really like it to have the type Num a => a since this can work with Ints or Doubles. With the MR turned off the compiler won't specialize the type of y and everything works as expected. The alternative is to give y an explicit type signature, but why do all that work when we can make the compiler do it for us?

bheklilr
  • 53,530
  • 6
  • 107
  • 163
  • Thanks for the explanation, bheklir. Adding NoMonomorphismRestriction solved the problem, although adding the type signature Lens' IL [Int] did not work. – user3458168 Apr 24 '15 at 07:40
  • @user3458168 Odd, what version of GHC are you using? It worked just fine for me. – bheklilr Apr 24 '15 at 11:55