Family types cannot return RankN type - workarounds or alternatives?

I play with an expandable library of records, and I want to write a function fieldthat can operate as either Lens, and Traversalbased on whether the key Symbolin the key list. Type family defined:

type family LensOrTraversal key keys s t a b where
    LensOrTraversal key '[] s t a b = 
        Traversal s t a b
    LensOrTraversal key (key =: val ': xs) s t a b = 
        Lens s t a b
    LensOrTraversal key (foo =: bar ': xs) s t a b = 
        LensOrTraversal key xs s t a b

This code gives me an error:

/home/matt/Projects/hash-rekt/src/Data/HashRecord/Internal.hs:433:5: 
error:
    • Illegal polymorphic type: Traversal s t a b
    • In the equations for closed type family ‘LensOrTraversal’
      In the type family declaration for ‘LensOrTraversal’

Ideally, I would like to be able to reuse the name fieldfor lenses and walks, as this will allow you to write

>>> let testMap = empty & field @"foo" .~ 'a'
>>> :t testMap
HashRecord '["foo" =: Char]
>>> testMap ^. field @"foo" 
'a'
>>> testMap ^. field @"bar"
Type error
>>> testMap ^? field @"bar"
Nothing

which follows common idioms Lens. I can provide a function fieldTraversalthat does what I want, but I would prefer, if possible, to overload the name field. How would you get around this type family restriction?

+4
1

, Rank2 ( Functor, Applicative).

type Lens s t a b      = ∀ f . Functor f     => (a -> f b) -> s -> f t
type Traversal s t a b = ∀ f . Applicative f => (a -> f b) -> s -> f t

:

import GHC.Exts (Constraint)
type family FieldOpticConstraint key keys :: (* -> *) -> Constraint where
  FieldOpticConstraint key '[] = Applicative
  FieldOpticConstraint key (key =: val ': xs) = Functor
  FieldOpticConstraint key (_ ': xs) = FieldOpticConstraint key xs

field LensOrTraversal, Rank2 , .

+4

Source: https://habr.com/ru/post/1676315/


All Articles