Hold a lens in a record

134 views Asked by At

I have a record MyRecord for which I create lenses with makeLenses. I would like to have a field in that record which holds itself a lens but that is also accessible with a lens like the other fields.

This is my code to achieve this:

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE RankNTypes #-}

module Check where

import Lens.Micro ( Lens' )
import Lens.Micro.TH ( makeLenses )

data MyRecord a = 
  MyRecord { _normalField :: Int
           , _myField :: Lens' (String, String) a 
           }

makeLenses ''MyRecord

The code compiles fine if I write myField instead of _myField but this way no lens would be generated for it.

For the given code ghc outputs

/home/fabian/src/code-editor/app/Check.hs:11:1: error:
    • Illegal polymorphic type: Lens' (String, String) a2
      GHC doesn't yet support impredicative polymorphism
    • In the type signature:
        myField :: forall a_a5c6 a_a8tU.
                   Lens.Micro.Type.Lens (MyRecord a_a5c6) (MyRecord a_a8tU) (Lens' (String,
                                                                                    String) a_a5c6) (Lens' (String,
                                                                                                            String) a_a8tU)
   |
11 | makeLenses ''MyRecord

Can someone briefly explain what is going on here and if there is a nice solution to this?

1

There are 1 answers

0
bergey On

I believe the usual solution are rank-1 types like ALens. I don't know if the microlens family provides something similar.

The GHC manual explains the problem & the solution. It begins:

In general, GHC will only instantiate a polymorphic function at a monomorphic type (one with no foralls). [...] The definition of foo is rejected because one would have to instantiate id‘s type with b := (forall s. ST s a) -> a, and that is not allowed. Instantiating polymorphic type variables with polymorphic types is called impredicative polymorphism.