sevo
sevo

Reputation: 4609

Do I need Applicative Pretext for using Traversal with Lens?

I have a function that I believe is stricter than lens because of Applicative f context.

Prelude Text.XML.Lens Data.Maybe Data.String Text.XML> :t f
f :: Control.Applicative.Applicative f =>
     (Element -> f Element) -> Document -> f Document

This is because I obtained it from some Traversal.

Prelude Text.XML.Lens Data.Maybe Data.String Text.XML> let f = root ./ ell "parent"

I want to pass it to a function that expects a monomorphic ALens:

Prelude Text.XML.Lens Data.Maybe Data.String Text.XML> :t textFrom
textFrom
  :: Data.Text.Internal.Text
     -> s -> ALens s s Element Element -> Maybe Data.Text.Internal.Text
Prelude Text.XML.Lens Data.Maybe Data.String Text.XML> textFrom "groupId" pom f

But I don't really understand why this Applicative instance is needed. I must be using this API incorrectly. What am I doing wrong?

    No instance for (Control.Applicative.Applicative
                       (Control.Lens.Internal.Context.Pretext (->) Element Element))
      arising from a use of ‘f’
    In the third argument of ‘textFrom’, namely ‘f’
    In the expression: textFrom "groupId" pom f
    In an equation for ‘it’: it = textFrom "groupId" pom f
Prelude Text.XML.Lens Data.Maybe Data.String Text.XML> :t f
f :: Control.Applicative.Applicative f =>
     (Element -> f Element) -> Document -> f Document
Prelude Text.XML.Lens Data.Maybe Data.String Text.XML> :t textFrom
textFrom
  :: Data.Text.Internal.Text
     -> s -> ALens s s Element Element -> Maybe Data.Text.Internal.Text
Prelude Text.XML.Lens Data.Maybe Data.String Text.XML> textFrom "groupId" pom f

<interactive>:68:24:
    No instance for (Control.Applicative.Applicative
                       (Control.Lens.Internal.Context.Pretext (->) Element Element))
      arising from a use of ‘f’
    In the third argument of ‘textFrom’, namely ‘f’
    In the expression: textFrom "groupId" pom f
    In an equation for ‘it’: it = textFrom "groupId" pom f

Upvotes: 1

Views: 128

Answers (1)

Cirdec
Cirdec

Reputation: 24166

Short Answer

f isn't a Lens, so can't be used as ALens. When you see ALens as an argument to a function, it expects a Lens.

Long Answer

A polymorphic value that requires an Applicative instance can be used fewer places than a value that only requires a Functor.

Applicative f => (Element -> f Element) -> Document -> f Document -- :t f
Functor     f => (Element -> f Element) -> Document -> f Document -- :t Lens' Element Document

You'd like to pass f in place of an ALens s s Element Element. I'm going to work through what that type is. I'll use E in place of Element to keep this short

type ALens s t a b = LensLike (Pretext (->) a b) s t a b
     ALens s s E E = Lenslike (Pretext (->) E E) s s E E

The type gets really long when we substitute for LensLike. The only thing that's going on here is Pretext (->) E E is taking the place of f everywhere.

type LensLike f                  s t a b = (a -> f                  b) -> s -> f                  t
     LensLike (Pretext (->) E E) s s E E = (E -> (Pretext (->) E E) E) -> s -> (Pretext (->) E E) s

Comparing this to the type of f we have (I'm going to use D in place of Document to keep this short`.

Applicative f => (E -> f                  E) -> D -> f                  D  -- :t f
                 (E -> (Pretext (->) E E) E) -> s -> (Pretext (->) E E) s  -- ALens s s E E

In order to use a value of the first type where the second is needed there must be an Applicative instance for Pretext (->) E E, but a Pretext only has a Functor instance. If f were actually a Lens and was defined for any Functor instead of any Applicative it would work here. That's the source of the error you are getting.

Upvotes: 2

Related Questions