Search code examples
haskellfunctional-programminghaskell-lenshaskell-optics

Could not deduce (Contravariant f) arising from a use of ‘to’


I'm new to Haskell and I'm trying to transform the value I got from a Traversal like below

startedAt :: Traversal' Object Int
startedAt = ix "at" 
          . (_Integral 
            `failing`  _String . to timeComponent._Right 
            `failing` _String ._Integral)

timeComponent :: Text -> Either String Int
timeComponent t = ...

I'm getting this error

Could not deduce (Contravariant f) arising from a use of ‘to’
      from the context: Applicative f
        bound by the type signature for:
                   startedAt :: Traversal' Object Int
        at SomeModule/Optics.hs:80:1-34
      Possible fix:
        add (Contravariant f) to the context of
          the type signature for:
            startedAt :: Traversal' Object Int
    • In the first argument of ‘(.)’, namely ‘to timeComponent’
      In the second argument of ‘(.)’, namely ‘to timeComponent . _Right’
      In the second argument of ‘(.)’, namely
        ‘to timeComponent . _Right’

In other parts of the code, developers are already doing

doSomething :: Object -> First Int
doSomething l = First $ <same-code-as-above> 

As you can see it works when I inline it, but when I move it to a separate Optic like above, it throws error...

Ps: One more doubt, when should I give the type as Traversal instead of Prism?


Solution

  • Your optic is a Fold Object Int, not a Traversal' Object Int. If you write the type signature as:

    startedAt :: Fold Object Int
    

    then it will type check.

    The underlying problem is that to f produces a Getter, not a Traversal', and when you compose an optic out of traversals (like ix "at") and getters (like to timeComponent), you get a fold.