I am trying to learn about lenses by implementing it in Haskell. I have implemented the view combinator as follows:
{-# LANGUAGE RankNTypes #-}
import Control.Applicative
import Data.Traversable
type Lens s a = Functor f => (a -> f a) -> s -> f s
view :: Lens s a -> s -> a
view lens = getConst . lens Const
However when I try to use it in conjunction with traverse I get the following error message:
Prelude> :load Lens.hs
[1 of 1] Compiling Main ( Lens.hs, interpreted )
Ok, modules loaded: Main.
*Main> :t view traverse
<interactive>:1:6:
Could not deduce (Applicative f) arising from a use of ‘traverse’
from the context (Traversable t)
bound by the inferred type of it :: Traversable t => t a -> a
at Top level
or from (Functor f)
bound by a type expected by the context:
Functor f => (a -> f a) -> t a -> f (t a)
at <interactive>:1:1-13
Possible fix:
add (Applicative f) to the context of
a type expected by the context:
Functor f => (a -> f a) -> t a -> f (t a)
or the inferred type of it :: Traversable t => t a -> a
In the first argument of ‘view’, namely ‘traverse’
In the expression: view traverse
Unfortunately, I don't understand this error message. Please explain what it means and how I may fix it.
As the other answers already explain, the issue is that view expects something that works for any Functor f, but traverse only works if f is also Applicative (and there are functors which are not applicative).
In lens, the problem is solved by making the type of view not take a Rank2 argument (in fact, most functions in lens don't use the Lens type synonym, they always use something weaker). For your function, observe that view only ever uses f ~ Const. This is why you can change the type signature to:
view :: ((a -> Const a a) -> s -> Const a s) -> s -> a
The implementation can stay the same, but now view also works on traverse:
view traverse :: (Traversable t, Monoid a) => t a -> a
Note the extra Monoid constraint. This constraint appears because if you set f ~ Const a in traverse :: (Traversable t, Applicative f) => (a -> f a) -> t a -> f (t a), you need an instance Applicative (Const a). That instance has a Monoid constraint on a though. And this also makes sense, because the traversable might be empty or contain more than one element, so you need mempty and mappend.
tl;dr - According to your definition of Lens, a traverse cannot be a Lens because traverse doesn't work for all Functors.
Let's take a look at your types:
λ :set -XRankNTypes
λ :m +Control.Applicative Data.Traversable
λ type Lens s a = Functor f => (a -> f a) -> s -> f s
λ :t traverse
traverse
:: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
Now at this point we can see that traverse is, in one way, slightly more general than our Lens type - it can take a function
from a -> f b where our lens can only take functions from a -> f a.
Restricting it to that case is no problem, so we can say
λ :t traverse :: (Traversable t, Applicative f) => (a -> f a) -> t a -> f (t a)
traverse :: (Traversable t, Applicative f) => (a -> f a) -> t a -> f (t a)
:: (Applicative f, Traversable t) => (a -> f a) -> t a -> f (t a)
So now it's obvious that if traverse is to be a Lens, it must be a Lens (t a) a, since that's the only way to make the type variables line up.
So let's try that out.
λ :t traverse :: Lens (t a) a
<interactive>:1:1:
Could not deduce (Traversable t1) arising from a use of `traverse'
from the context (Functor f)
bound by the inferred type of
it :: Functor f => (a -> f a) -> t a -> f (t a)
at Top level
or from (Functor f1)
bound by an expression type signature:
Functor f1 => (a1 -> f1 a1) -> t1 a1 -> f1 (t1 a1)
at <interactive>:1:1-24
Possible fix:
add (Traversable t1) to the context of
an expression type signature:
Functor f1 => (a1 -> f1 a1) -> t1 a1 -> f1 (t1 a1)
or the inferred type of
it :: Functor f => (a -> f a) -> t a -> f (t a)
In the expression: traverse :: Lens (t a) a
Oof, it didn't like that. Oh, wait, in order to use traverse our type t has to be Traversable, so let's add that restriction. (Just like the "Possible fix") suggests:
λ :t traverse :: Traversable t => Lens (t a) a
<interactive>:1:1:
Could not deduce (Applicative f1) arising from a use of `traverse'
from the context (Functor f, Traversable t)
bound by the inferred type of
it :: (Functor f, Traversable t) => (a -> f a) -> t a -> f (t a)
at Top level
or from (Traversable t1, Functor f1)
bound by an expression type signature:
(Traversable t1, Functor f1) =>
(a1 -> f1 a1) -> t1 a1 -> f1 (t1 a1)
at <interactive>:1:1-41
Possible fix:
add (Applicative f1) to the context of
an expression type signature:
(Traversable t1, Functor f1) =>
(a1 -> f1 a1) -> t1 a1 -> f1 (t1 a1)
or the inferred type of
it :: (Functor f, Traversable t) => (a -> f a) -> t a -> f (t a)
In the expression: traverse :: Traversable t => Lens (t a) a
Ok, so the problem now is that it can't infer that f is Applicative (which is also required to use traverse), just that it's a Functor (which it gets from the definition of Lens).
We can't add Applicative f to the context though - the f is hidden. When we say type Lens s a = Functor f => (a -> f a) -> s -> f s, we're saying that the Lens has to work for all Functors.
But traverse only works for the subset of Functors that are also Applicative. So in this way the type of traverse is more specific than is allowed for Lenses.
traverse has this type:
traverse :: (Applicative f, Traversable t) => (x -> f y) -> t x -> f (t y)
If we make the free variable f in the type definition of Lens explicit, its definition is actually
type Lens s a = forall f . Functor f => (a -> f a) -> s -> f s
So view wants a function that can operate on any Functor, whereas traverse can only operate on an Applicative.
You can fix the error simply by changing Functor into Applicative in the definition of Lens, but I'm not sure if that's exactly what you would want to achieve here.
Related
Suppose we have some class Foo such that an instance of Foo f gives us everything necessary to implement Functor f, Foldable f and Traversable f. To avoid overlapping instances, can witness this relationship between Foo and Functor, Foldable, Traversable under a newtype wrapper:
type Foo :: (Type -> Type) -> Constraint
class Foo f
where
{- ... -}
type FoonessOf :: (Type -> Type) -> Type -> Type
newtype FoonessOf f a = FoonessOf (f a)
instance Foo f => Functor (FoonessOf f)
where
fmap = _
instance Foo f => Foldable (FoonessOf f)
where
foldMap = _
instance Foo f => Traversable (FoonessOf f)
where
traverse = _
Now suppose we have some type constructor:
data Bar a = Bar {- ... -}
such that there is an:
instance Foo Bar
where
{- ... -}
We'd like to equip Bar with the instances implied by its "Foo-ness". Since Bar a is Coercible to FoonessOf Bar a, we'd expect to be able to derive the instances via the FoonessOf Bar:
deriving via (FoonessOf Bar) instance Functor Bar
deriving via (FoonessOf Bar) instance Foldable Bar
And this works handily for typeclasses such as Functor and Foldable
Unfortunately when we try to do the same thing with Traversable, things go awry:
[typecheck -Wdeferred-type-errors] [E] • Couldn't match representation of type ‘f1 (Foo Bar a1)’
with that of ‘f1 (Bar a1)’
arising from a use of ‘ghc-prim-0.6.1:GHC.Prim.coerce’
NB: We cannot know what roles the parameters to ‘f1’ have;
we must assume that the role is nominal
• In the expression:
ghc-prim-0.6.1:GHC.Prim.coerce
#(Foo Bar (f a) -> f (Foo Bar a)) #(Bar (f a) -> f (Bar a))
(sequenceA #(Foo Bar)) ::
forall (f :: TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep
-> TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep)
(a :: TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep).
Applicative f => Bar (f a) -> f (Bar a)
In an equation for ‘sequenceA’:
sequenceA
= ghc-prim-0.6.1:GHC.Prim.coerce
#(Foo Bar (f a) -> f (Foo Bar a)) #(Bar (f a) -> f (Bar a))
(sequenceA #(Foo Bar)) ::
forall (f :: TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep
-> TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep)
(a :: TYPE ghc-prim-0.6.1:GHC.Types.LiftedRep).
Applicative f => Bar (f a) -> f (Bar a)
When typechecking the code for ‘sequenceA’
in a derived instance for ‘Traversable Bar’:
To see the code I am typechecking, use -ddump-deriv
In the instance declaration for ‘Traversable Bar’
——————————————————————————————————————————————————————————————————————————————
...
So the questions I have are:
Is it possible to come up with some other scheme for deriving-via the instance Traversable Bar?
Is it possible to come up with some modification of the Traversable class that can be derived via a newtype?
I suspect the answer to 1. is: no, the situation cannot be salvaged, and it is impossible to obtain an instance of Traversable using DerivingVia.
As far as 2. goes, it's useful to try and reproduce the problem in a simpler context. Consider the following:
-- Remember to turn on ScopedTypeVariables!
data A = A
newtype B = B A
a :: forall f. f A -> f A
a = id
b :: forall f. f B -> f B
b = coerce $ a #f
It seems like this should work, but alas:
[typecheck -Wdeferred-type-errors] [E] • Couldn't match representation of type ‘f A’ with that of ‘f B’
arising from a use of ‘coerce’
NB: We cannot know what roles the parameters to ‘f’ have;
we must assume that the role is nominal
• In the expression: coerce $ a #f
In an equation for ‘b’: b = coerce $ a #f
• Relevant bindings include
b :: f B -> f B
The problem has to do with the "roles" of type constructors' parameters, and the way role inference works. For our purposes, roles come in two varieties: "representational" and "non-representational". Also for our purposes, the difference between the two can be approximated to the following: a type constructor F :: Type -> Type has a parameter of a "representational" role if there is an instance of Representational F, where:
type Representational :: (Type -> Type) -> Constraint
type Representational f = forall x y. Coercible x y => Coercible (f x) (f y)
Otherwise, the parameter of F is non-representational.
The typechecker lets you annotate the roles of type parameters in various places (although strangely enough, not in the kind). Sadly, there is no way to annotate the roles of a higher kinded type variable. What we can do however is just ask for Representational f directly:
b' :: forall f. Representational f => f B -> f B
b' = coerce $ a #f
which now typechecks. This suggests a possible way to tweak the Traversable typeclass to make it derivable via coercions.
Now let's look at the type of the Traversable operation sequenceA:
class Traversable t
where
sequenceA :: forall f. Applicative f => forall a. t (f a) -> f (t a)
{- ... -}
NB: There's that pesky forall f again, meaning f is taken to have a type parameter of a nominal role.
What DerivingVia is going to do is attempt to coerce between:
sequenceA #T1 :: forall f. Applicative f => forall a. T1 (f a) -> f (T2 a)
and:
sequenceA #T2 :: forall f. Applicative f => forall a. T2 (f a) -> f (T2 a)
Despite T1 (FoonessOf Bar) and T2 (Bar) being "parametrically" coercible, this coercion will fail, because the coercion of the entire operation will decompose eventually to the coercion the typechecker complained about:
Couldn't match representation of type
‘f1 (Foo Bar a1)’
with that of
‘f1 (Bar a1)’
This doesn't work because of f's parameter being considered to have a nominal role, as we discussed.
As with our simplified example above, the fix is straightforward: just ask for Representational f:
type Traversable' :: (Type -> Type) -> Constraint
class Traversable' t
where
traverse :: (Representational f, Applicative f) => (a -> f b) -> t (f a) -> f (t b)
And now at last we can derive an instance of Traversable' via the FoonessOf Bar:
instance Foo f => Traversable' (FoonessOf f)
where
traverse = _
deriving via (FoonessOf Bar) instance Traversable' Bar
I'm working through the Haskell book and I've realized I'm having a hard time understanding function composition. At a very basic level I have a mental model of a pipeline that takes an input and passes it's result to the next function in the composition. For simple functions this is very easy.
Where I'm having difficulty is understanding how the resulting type signatures of composing the functions come to be. For example, if we look at the base definition of elem:
elem :: (Foldable t, Eq a) => a -> t a -> Bool
elem = any . (==)
>:t (==)
(==) :: Eq a => a -> a -> Bool
>:t any
any :: Foldable t => (a -> Bool) -> t a -> Bool
I fail to see how the resulting type signature occurs. If I were given the function and asked to write the type signature I'd be hopelessly lost.
The same goes for the following. In the chapter on Traversable we were told that traverse is just sequenceA and fmap composed:
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f
>:t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
>:t sequenceA
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
On their own I understand each functions type signature, but how do they combine to create traverse's type signature?
Super lost here, any help would be greatly appreciated.
Perhaps merely visually aligning the types will get you part of the way to some intuition about how the pipeline progresses, and help you make progress towards your next point of confusion!
(==) :: Eq a => a -> (a -> Bool)
any :: (a -> Bool) -> (t a -> Bool)
any . (==) :: Eq a => a -> (t a -> Bool)
To keep the next one on one screen, let's abbreviate Traversable to T and Applicative to A. You also have two fs in your question, one at the computation level and one at the type level. To avoid confusion, I'm going to rename your computation-level f to g instead. So if g :: a -> f b for some Applicative f:
fmap g :: T t => t a -> t (f b)
sequenceA :: (T t, A f) => t (f b) -> f (t b)
sequenceA . fmap g :: (T t, A f) => t a -> f (t b)
\g -> sequenceA . fmap g :: (T t, A f) => (a -> f b) -> t a -> f (t b)
(Wait! How come for fmap g, the constraint on t is Traversable and not Functor? Okay, no problem: we can actually give it the more relaxed type fmap g :: Functor t => .... But since every Traversable must be a Functor, it can also be given this type which makes the parallels more clear.)
All Haskell functions take just one argument -- even the ones we often think of as taking multiple arguments. Consider your elem example:
elem :: (Foldable t, Eq a) => a -> t a -> Bool
elem = any . (==)
>:t (==)
(==) :: Eq a => a -> a -> Bool
>:t any
any :: Foldable t => (a -> Bool) -> t a -> Bool
The type of (==) can be read as (==) :: Eq a => a -> (a -> Bool): it takes an a value (a can be anything which is an instance of Eq) and gives an a -> Bool function. any, in turn, takes an a -> Bool function (a can be anything) and gives a t a -> Bool function (t can be anything which is an instance of Foldable). That being so, the intermediate type in the any . (==) pipeline is Eq a => a -> Bool.
I'm developing a class representing key/value mappings, and I've got a function which is basically like alterF:
class C t where
...
alterF :: Functor f =>
(Maybe (Value t) -> f (Maybe (Value t))) -> Key t -> t -> f t
Unfortunately, this breaks GeneralisedNewtypeDeriving. In some cases, this is reasonable, as GeneralisedNewtypeDeriving from what I understand essentially uses Coercible and the function coerce. Coercible represents types which are representationally equal, i.e. they have the same representation at run time, so we can convert between them for free. For example, given:
newtype T a = T a
we have:
Coercible a (T a)
Coercible (T a) a
but we don't have (in general):
Coercible (f a) (f (T a))
Coercible (f (T a)) (f a)
For example, GADTs violate this representational equality. But there are lots of values of f that do work. For example:
Coercible (Maybe a) (Maybe (T a))
Coercible (Maybe (T a)) (Maybe a)
Coercible [a] [T a]
Coercible [T a] [a]
Coercible (Identity a) (Identity (T a))
Coercible (Identity (T a)) (Identity a)
It also occurs to me that this instance could be written:
Functor f => Coercible (f a) (f (T a))
Functor f => Coercible (f (T a)) (f a)
Just using fmap. Unlike the usual coerce, this wouldn't be free at runtime, but it will work.
So I've got a class with 10 functions, 9 of which work fine with GeneralisedNewtypeDeriving. There's just this final one which doesn't, which could be resolved mechanically using fmap. Do I have to write custom wrapping/unwrapping implementations for all my class functions, or is there a way to either require me to write the implementation for just the problem function or alternatively coax GHC into using fmap as part of it's GeneralisedNewtypeDeriving?
If f is a Functor, you can make a "representational wrapper" for it
data Rep f a where
Rep :: (b -> a) -> f b -> Rep f a
which is isomorphic to f except that it is representational in a, by what is essentially existential quantification over any nominal variance f might have. I think this construction happens to have some fancy category theory name but I don't remember what it is. To get the f a back out of a Rep f a, you need to use f's Functorhood.
You can use this wrapper in your method, ensuring that your class varies representationally.
alterFRep :: (Functor f)
=> (Maybe (Value t) -> Rep f (Maybe (Value t))) -> Key t -> t -> Rep f t
And then make the real "method" just a regular function in terms of it by using the isomorphism with Rep f. You can also make a convenience method for instance authors:
toAlterFRep ::
(forall f t. (Functor f) => (Maybe (Value t) -> f (Maybe (Value t))) -> Key t -> t -> f t)
-> (forall f t. (Functor f) => (Maybe (Value t) -> Rep f (Maybe (Value t))) -> Key t -> t -> Rep f t)
so they don't have to worry about what the heck Rep is, they just implement alterF normally and use toAlterFRep on it.
Why does GHCI add constraint for the required context here:
> let f = fmap show
> :t f
f :: (Functor f, Show a) => f a -> f String
But not here?
> :t over
over :: Lens s t a b -> (a -> b) -> s -> t
> :t _all'
_all' :: (Applicative f, Eq a) => a -> (a -> f a) -> [a] -> f [a]
> :t over (_all' 2)
<interactive>:1:7: error:
• Could not deduce (Applicative f) arising from a use of ‘_all'’
Is there any major difference between these two cases?
Note that isn't the type of over as defined by the lens library. That being said, your version doesn't work because Lens is
type Lens = forall f. Functor f => (a -> f b) -> s -> f t
and
_all' 2 :: forall f. Applicative f => ..
In other words, over is demanding a function which works for any Functor, but you've provided one which only works for Applicative (which is a stronger constraint, in that Functor doesn't imply Applicative).
Comment by #user2407038.
As alluded to in the comment, you can fix your problem by fixing the type signature for over. It should either be the complicated fancy thing in lens using distributive functors or the simpler
type Setter s t a b = (a -> Identity b) -> s -> Identity t
over :: Setter s t a b -> (a -> b) -> s -> t
As the identity type is both a functor and an applicative, it unifies with lenses and (I assume in your case) traversals.
Typeclassopedia presents Traversable:
class (Functor t, Foldable t) => Traversable t where
traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
sequenceA :: Applicative f => t (f a) -> f (t a)
mapM :: Monad m => (a -> m b) -> t a -> m (t b)
sequence :: Monad m => t (m a) -> m (t a)
A good exercise is to figure out what the default implementations should be: given either traverse or sequenceA, how would you define the other three methods?
I came up with the following code that type-checks:
class (Functor t, Foldable t) => MyTraversable t where
traverse' :: Applicative f => (a -> f b) -> t a -> f (t b)
traverse' = error "..."
sequenceA' :: Applicative f => t (f a) -> f (t a)
sequenceA' f = traverse' id f
mapM :: Monad m => (a -> m b) -> t a -> m (t b)
mapM = traverse'
sequence' :: Monad m => t (m a) -> m (t a)
sequence' = sequenceA'
If my implementations of mapM and sequence' are correct, and, since every Monad is an Applicative:
λ: :i Monad
class Applicative m => Monad (m :: * -> *) where
...
then it's not clear to me why mapM and sequence' are even necessary. Why are they?
P.S. - Credit and my thanks to haoformayor for helping me out with sequenceA.
As mentioned in the comments, there was a time when not every Monad was an Applicative.
Just recently (in base-4.8 which shipped with GHC 7.10) the Applicative was made a superclass of Monad. You might have seen Applicative-Monad-Proposal, AMP.
Currently the Monad of no return, MRP (email-thread) is worked on, which will make
Monad's >> and Applicative's *> the same. Which eventlually would make possible to say that traverse = mapM and sequence = sequenceA. But that is a long process, which will take time.
So to answer your question: for history reasons.