Search code examples
haskelllenses

Type failure when using 'left' Lens from fclabels


I've made a minimal example for testing out fclabels. Using a lens to retrieve a 'right' value from an Either value. Why does this fail? Have I missed including something?

module Label where
import Data.Label
import Data.Label.Base

test = get right (Right "test")

{- Will fail with this message:
Label.hs:5:12:
    No instance for (Control.Arrow.ArrowZero Data.Label.Point.Total)
      arising from a use of `right'
    Possible fix:
      add an instance declaration for
      (Control.Arrow.ArrowZero Data.Label.Point.Total)
    In the first argument of `get', namely `right'
    In the expression: get right (Right "test")
    In an equation for `test': test = get right (Right "test")
Failed, modules loaded: none.

-- Tested with fclabels-2.0.2
-}

Solution

  • The error is rather obscure, but it becomes clearer when we look at the types and documentation of get and right:

    get :: (f :-> a) -> f -> a
    type :-> f o = Lens Total f o
    
    right :: (ArrowZero arr, ArrowApply arr, ArrowChoice arr)
          => Lens arr (Either a b -> Either a o) (b -> o)
    
    -- Lens pointing to the right value in an Either. (Partial and polymorphic)
    

    Essentially the get you're using is only for total lenses, but right isn't a total lens as it wouldn't work if the value was a Left. The error is saying that a partial lens requires the carrier type to be an ArrowZero, but that total lenses can't do that.

    If you experiment in ghci, you get this error just from calling get right, without any arguments.

    If you change the import of Data.Label to Data.Label.Partial, then your code works. test ends up with the type Maybe String.