Haskell Lens: Let the binding Traversal '

I'm a little confused and don't know where to look for information / explanation of the next "problem" (this is not a problem in itself, but rather a situation where I don't understand what is wrong behind the scenes):

I have a monad transformer stack with StateT . At some point in my function, I would like to bind a small portion of my state to a local variable so that I can refer to it instead of writing the entire path to the chunk of the state I'm interested in. Here's what I look like:

{-# LANGUAGE ScopedTypeVariables #-}

...

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

      

Now this won't compile:

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

      

But if I translate the reference to that data block to the function, then everything compiles fine:

someFunction :: MyMonad ()
someFunction = do
  ...
  let x = clientData clientIdx dataIdx
  ...

  where clientData :: Int -> Int -> Traversal' MyState MyDataT
        clientData clientIdx dataIdx = myState.clients.ix clientIdx.someData.ix dataIdx

      

I am looking for some information to help me understand what is happening here, why this is happening, so that I know what I am doing wrong. Basically I would like to expand my knowledge to understand this use case a little better.

+3


source to share


1 answer


The key point here is that the annotation should be on a separate line. If we do that, we have an explicit type binding as far as GHC is concerned.

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

      

What you have very rarely tried for the first time works as you planned:

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

      

This is a binding without an explicit type; the annotation is inside the left side. GHC considers the type of the variable to be fixed before looking at the right side, but the annotation only applies to the left side, so GHC just injects the type for the right side separately and then tries to match it exactly to the annotation.This makes the type checking fail for all but the simplest not polymorphic cases.



The correct way to place annotations inside bindings is as follows:

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

      

Here, GHC first assigns to a variable the "malleable" undefined type of the variable x

, then injects the type for the right-hand side as reported by the annotation there, and then concatenates the type with it x

.

This is still a bind without an explicit type, but it works at all if we enable it NoMonomorphismRestriction

for the reasons described in this fooobar.com/questions/264110 / ... question .

+6


source







All Articles