Applicative instance trying to use monoidal functors - haskell

I'm learning Haskell and trying to do exercises from book Haskell Programming from first principles and I'm stack trying to write applicative for Pair type
data Pair a = Pair a a deriving Show
I have seen some other examples on web but I'm trying somewhat different applicative functor, I'm trying to utilize monoidal structure of this type. Here is what I have
data Pair a = Pair a a deriving (Show, Eq)
instance Functor Pair where
fmap f (Pair x y) = Pair (f x) (f y)
instance Semigroup a => Semigroup (Pair a) where
(Pair x y) <> (Pair x' y') = Pair (x <> x') (y <> y')
instance Applicative Pair where
pure x = Pair x x
(Pair f g) <*> p = fmap f p <> fmap g p
Unfortunately this will not compile:
* No instance for (Semigroup b) arising from a use of `<>'
Possible fix:
add (Semigroup b) to the context of
the type signature for:
(<*>) :: forall a b. Pair (a -> b) -> Pair a -> Pair b
* In the expression: fmap f p <> fmap g p
In an equation for `<*>': (Pair f g) <*> p = fmap f p <> fmap g p
In the instance declaration for `Applicative Pair'
And this is where I'm stack; I don't see how can I add typeclass constraint to Applicative definition and I thought that making type Pair instance of Semigroup is enough.
Other solutions that I have seen are like
Pair (f g) <*> Pair x y = Pair (f x) (g y)
but these solutions don't utilize monoidal part of Pair type
Is it even possible to make this applicative the way I't trying?

Although it's true that Applicative is the class representing monoidal functors (specifically, Hask endofunctors which are monoidal), Allen&Moronuki present this unfortunately in a way that seems to suggest a direct relation between the Monoid and Applicative classes. There is, in general, no such relation! (The Writer type does define one particular Applicative instance based on the Monoid class, but that's an extremely special case.)
This spawned a rather extended discussion at another SO question.
What the “monoidal” in “monoidal functor” refers to is a monoidal structure on the category's objects, i.e. on Haskell types. Namely, you can combine any two types to a tuple-type. This has per se nothing whatsoever to do with the Monoid class, which is about combining two values of a single type to a value of the same type.
Pair does allow an Applicative instance, but you can't base it on the Semigroup instance, although the definition actually looks quite similar:
instance Applicative Pair where
pure x = Pair x x
Pair f g <*> Pair p q = Pair (f p) (g q)
However, you can now define the Semigroup instance in terms of this:
instance Semigroup a => Semigroup (Pair a) where
(<>) = liftA2 (<>)
That, indeed, is a valid Semigroup instance for any applicative, but it's usually not the definition you want (often, containers have a natural combination operation that never touches the contained elements, e.g. list concatenation).

I don't think that Pair is an Applicative the way you want it to be, Applicative states that
(<*>) :: f (a -> b) -> f a -> f b
should work for all functions in first position whereas you want
(<*>) :: Semigroup b => f (a -> b) -> f a -> f b.
If Pair was always a Semigroup (like Maybe or List for example) your reasoning would be sound, but you need the pre-requisite of the Pair-containee to be Semigroup.

Correct: Pair can't be made an Applicative in the way you want, because Applicative f demands that f a "feel applicative-y" for any a, even non-Semigroup as. Consider writing an alternative class and implementing it:
class CApplicative f where
type C f
pure :: C f a => a -> f a
app :: C f b => f (a -> b) -> f a -> f b
instance CApplicative Pair where
type C Pair = Semigroup
pure x = Pair x x
app (Pure f g) p = fmap f p <> fmap g p

This can be derive since base 4.17.0.0, which includes the via types Generically and Generically1. This will derive the same instances as leftaroundabout writes:
{-# Language DeriveGeneric #-}
{-# Language DerivingStrategies #-}
{-# Language DerivingVia #-}
import Data.Monoid
import GHC.Generics
data Pair a = Pair a a
deriving
stock (Generic, Generic1)
deriving (Semigroup, Monoid)
via Generically (Pair a)
deriving (Functor, Applicative)
via Generically1 Pair
Alternatively you can lift Semigroup and Monoid through the Applicative
deriving (Semigroup, Monoid, Num)
via Ap Pair a

Related

Applicative Instance of Pair Data Type in Haskell

I am trying to implement this pair data type as an applicative functor but I am told that 'a' is not in scope. I thought already stated what 'a' was in the instance declaration.
data Pair a b = Pair a b deriving (Show)
instance Functor (Pair a) where
fmap f (Pair a b) = Pair a (f b)
instance Applicative (Pair a) where
pure x = Pair a x
Pair a f <*> Pair a' x = Pair (a + a') (f x)
a is a type variable, not something you can use in the definition of pure. pure needs some way of getting a value of type a to pair with x. There are a few ways you could do that:
A function of type b -> a that you could apply to x.
A function of type () -> a that you could apply to ().
Some predefined value of type a.
The Applicative instance of (,) a takes the third approach, by requiring that a have a Monoid instance so that you can define pure in terms of mempty.
instance Monoid a => Applicative (Pair a) where
pure x = Pair mempty x
Pair a f <*> Pair a' x = Pair (a <> a') (f x)
In your definition, you assumed that (+) is defined for the a values, which means you are missing a Num constraint, but also that you could simply use 0 in your definition of pure.
instance Num a => Applicative (Pair a) where
pure x = Pair 0 x
Pair a f <*> Pair a' x = Pair (a + a') (f x)
You can also derive it via the new Generically1 applied to Sum a
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DerivingVia #-}
import GHC.Generics (Generic1, Generically1(..))
import Data.Monoid (Sum(..))
data Pair a b = Pair a b
deriving
stock (Show, Generic1)
deriving (Functor, Applicative)
via Generically1 (Pair (Sum a))

Why are traversals defined over Applicatives, fundamentally?

I've been on a bit of a "distilling everything to its fundamentals" kick lately, and I've been unable to find clear theoretical reasons for how the Traversable typeclass is defined, only practical ones of "it's useful to be able to traverse over applicative coalgebras, and lots of datatypes can do it" and a whole lot of hints.
I'm aware that there's an applicative "family", as described by https://duplode.github.io/posts/divisible-and-the-monoidal-quartet.html.
I'm also aware that while Traversable traversals are applicative coalgebras, the Traversable1 typeclass from 'semigroupoids' describes apply coalgebras, and the Distributive typeclass from 'distributive' describes functor algebras.
Additionally, I'm aware that Foldable, Foldable1, and theoretical fold family members, describe datatypes that can be folded using monoids, semigroups, and corresponding monoid family members such as magmas (for folding as a binary tree) and commutative versions of each (for folding as unordered versions of each).
As such, as Traversable is a subclass of Foldable, I assume it's monoidal in nature, and similarly I assume Traversable1 is semigroupal in nature, and Distributive is comonoidal in nature (as mentioned in its description in the 'distributive' package).
This feels like the right track, but where do Applicative and Apply come from here? Are there magmatic and commutative versions? Would there be a distributive family in a category with non-trivial comonoids?
Essentially, my question is "do these typeclasses exist, and what are they? if not, why not?":
class FoldableMagma t => TraversableMagma t where
traverseMagma :: ??? f => (a -> f b) -> (t a -> f (t b))
class FoldableCommute t => TraversableCommute t where
traverseCommute :: ??? f => (a -> f b) -> (t a -> f (t b))
class Foldable t => ContraTraversable t where
contraTraverse :: Divisible f => (b -> f a) -> (t a -> f (t b))
-- im really not sure on this last one
-- but it's how i'd expect an endofunctor over coalgebras to look
-- which seems potentially related to traversables?
Presumably less important bonus question: while attempting to research this, I came across the 'data-functor-logistic' package https://hackage.haskell.org/package/data-functor-logistic
This describes a version of Distributive over contravariant functors - is there an equivalent Traversable over Divisibles (or Decidables)?
I'm not aware of any library that implements those classes, but I'll try to unravel what those classes would represent. I am a programmer, not a category theorist, so take this with a grain of salt.
Applicative variants
ApplyMagma
The ApplyMagma class has exactly the same methods as the Apply class, but it doesn't need to follow the associativity law.
class Functor f => ApplyMagma f where
(<.>) :: f (a -> b) -> f a -> f b
If Apply is analogous to semigroups, ApplyMagma is analogous to magmas.
ApplyCommute
The ApplyCommute class will be equivalent to the Apply class but with the following commutativity law:
f <$> x <.> y = flip f <$> y <.> x
If Apply is analogous to semigroups, ApplyCommute is analogous to commutative semigroups.
Traversable1 variants
Traversable1Magma
A Traversable1Magma can be seen as a Traversable1 with more information provided about the structure. While the Foldable1 class has a toNonEmpty method, The Foldable1Magma class could have a toBinaryTree method.
class (FoldableMagma t, Traversable1 t) => Traversable1Magma t where
traverseMagma :: ApplyMagma f => (a -> f b) -> (t a -> f (t b))
Traversable1Commute
A Traversable1Commute can be seen as a Traversable1 without a defined ordering to the elements. If it didn't require an Ord a constraint, Set from containers could be an instance of this class. Traversable1Commute could be a superclass of Traversable1.
class (FoldableCommute t, Functor t) => Traversable1Commute t where
traverseCommute :: ApplyCommute f => (a -> f b) -> (t a -> f (t b))
Note that these are variants of Traversable1 because neither ApplyMagma nor ApplyCommute have a function equivalent to pure.
ContraTraversable
ContraTraversable does not have any instances. To see why, look at the type of the contraTraverse function.
contraTraverse :: Divisible f => (b -> f a) -> (t a -> f (t b))
We can specialize this to the following:
contraTraverse :: Monoid b => (b -> Op b a) -> (t a -> Op b (t b))
Which is eqivalent to the following:
contraTraverse ~ Monoid b => (b -> a -> b) -> t a -> t b -> a
Using const and the conquer function from Divisible, this allows us to create a value of any type, which is impossible.
Since asking this and receiving the previous (excellent) answer, I have learnt another reason why Applicative is used: algebraic datatypes!
Without any constraint, it can only describe uninhabited datatypes, like this:
data V1 a
instance VTraversable V1 where
vtraverse _ = \case
-- uninhabited types can be pattern matched to create any result type
If it were Functor, it could describe algebraic datatypes that look something like these:
data FTrav1 a = FTrav1 a
instance FTraversable FTrav1 where
ftraverse strat (FTrav1 a) = FTrav1 <$> strat a
data FTrav2 a = FTrav2_1 a | FTrav2_2 (FTrav1 a)
instance FTraversable FTrav2 where
ftraverse strat (FTrav2_1 a) = FTrav2_1 <$> strat a
ftraverse strat (FTrav2_2 fa) = FTrav2_2 <$> ftraverse strat fa
Essentially, it's any datatype with an arbitrary (potentially infinite, if that were describable in Haskell) number of constructors of a single FTraversable argument (where a ~ Identity a). This is saying that any Traversable f a is isomorphic to (f (), a), the Writer functor.
Introducing Apply enables extra datatypes like the following:
data ApplyTrav1 a = ApplyTrav1 a a
instance Traversable1 ApplyTrav1 where
traverse1 strat (ApplyTrav1 a a) = ApplyTrav1 <$> strat a <*> strat a
data ApplyTrav2 a = ApplyTrav2_1 a (ApplyTrav1 a) | ApplyTrav2_2 (ApplyTrav1 a) a
instance Traversable1 ApplyTrav2 where
traverse1 strat (ApplyTrav2_1 a fa) = ApplyTrav2_1 <$> strat a <*> traverse1 strat fa
traverse1 strat (ApplyTrav2_2 fa a) = ApplyTrav2_2 <$> traverse1 strat fa <*> traverse1 strat a
Now constructors can have arbitrarily many arguments, as long as it's a finite number greater than zero! The isomorphism is now to (f (), NonEmpty a), where they are of equal sizes.
Applicative enables the following:
data ApplicTrav a = ApplicTrav0 | ApplicTrav a a
instance Traversable ApplicTrav where
traverse _ ApplicTrav0 = pure ApplicTrav0
traverse strat (ApplicTrav a a) = ApplicTrav <$> strat a <*> strat a
Now empty constructors are allowed! The isomorphism is now to (f (), [a]).
A hypothetical commutative Applicative would be used for commutative algebraic datatypes, were they a thing - perhaps, if Set enforced that it were only foldable with commutative monoids, they would be relevant! But to my knowledge, commutative datatypes are not a core part of Haskell, and so this form of traversal will not show up for algebraic datatypes.
Distributive is similar, it describes functors with a single constructor of arbitrarily many records (potentially infinite).
Logistic is unrelated to this algebraic interpretation, to my knowledge - since the Reader functor is commonly used with Distributives to create a collection of getter functions, Logistic is designed to work with the Op contravariant functor to create a collection of setter functions.
This suggests to me that the equivalent for Traversable doesn't exist, due to the Writer functor that characterises Traversables being its own opposite ((r,a) is isomorphic to (a,r)).

What is the Applicative's pure for Data Two a b = Two a b

Given this type:
data Two a b = Two a b deriving (Eq, Show)
What would be the Applicative definition. I'm not able to get the pure right without adding a constraint on a like for example Num a
instance (Num a, Monoid a) => Applicative (Two a) where
pure b = Two 1 b
Two f f' <*> Two a b = Two a (f' b)
You can't have it without a constraint. You need to do something about a and to be able to you need to have operations for that type, which you can get two ways: either use a specific type (e.g., Int, or an abstract one, requiring a typeclass instance).
The most general constraint that comes to mind in such a case is Monoid, which renders your instance the same as for the 2-element tuple:
instance Monoid a => Applicative ((,) a) where
pure x = (mempty, x)
(u, f) <*> (v, x) = (u `mappend` v, f x)

List of Functors

This might apply for any type class, but lets do it for Functors as I know them better. I wan't to construct this list.
l = [Just 1, [1,2,3], Nothing, Right 4]
and then
map (fmap (+1)) l
to get
[Just 2, [2,3,4], Nothing, Right 5]
I know they are all Functors that contain Ints so it might be possible. How can I do this?
Edit
This is turning out to be messier than it would seem. In Java or C# you'd declare the IFunctor interface and then just write
List<IFunctor> l = new List<IFunctor> () {
new Just (1),
new List<Int>() {1,2,3},
new Nothing<Int>(),
new Right (5)
}
assuming Maybe, List and Either implement the IFunctor. Naturally Just and Nothing extend Maybe and Right and Left extend Either. Not satisfied with this problem being easier to resolve on these languages!!!
There should cleaner way in Haskell :(
In Haskell, downcasting is not allowed. You can use AnyFunctor, but the trouble with that is there is no longer any way to get back to a functor that you know. When you have an AnyFunctor a, all you know is that you have an f a for some f, so all you can do is fmap (getting you another AnyFunctor). Thus, AnyFunctor a is in fact equivalent to ().
You can add structure to AnyFunctor to make it more useful, and we'll see a bit of that later on.
Functor Coproducts
But first, I'll share the way that I would probably end up doing this in a real program: by using functor combinators.
{-# LANGUAGE TypeOperators #-}
infixl 1 :+: -- declare this to be a left-associative operator
data (f :+: g) a = FLeft (f a) | FRight (g a)
instance (Functor f, Functor g) => Functor (f :+: g) where
-- left as an exercise
As the data type reads, f :+: g is a functor whose values can be either f a or g a.
Then you can use, for example:
l :: [ (Maybe :+: []) Int ]
l = [ FLeft (Just 1), FRight [2,3,4], FLeft Nothing ]
And you can observe by pattern matching:
getMaybe :: (Maybe :+: g) a -> Maybe a
getMaybe (FLeft v) = v
getMaybe (FRight _) = Nothing
It gets ugly as you add more functors:
l :: [ (Maybe :+: [] :+: Either Int) Int ]
l = [ FLeft (FLeft Nothing), FRight (Right 42) ]
-- Remember that we declared :+: left-associative.
But I recommend it as long as you can handle the ugliness, because it tracks the list of possible functors in the type, which is an advantage. (Perhaps you eventually need more structure beyond what Functor can provide; as long as you can provide it for (:+:), you're in good territory.)
You can make the terms a bit cleaner by creating an explicit union, as Ganesh recommends:
data MyFunctors a
= FMaybe (Maybe a)
| FList [a]
| FEitherInt (Either Int a)
| ...
But you pay by having to re-implement Functor for it ({-# LANGUAGE DeriveFunctor #-} can help). I prefer to put up with the ugliness, and work at a high enough level of abstraction where it doesn't get too ugly (i.e. once you start writing FLeft (FLeft ...) it's time to refactor & generalize).
Coproduct can be found in the comonad-transformers package if you don't want to implement it yourself (it's good exercise though). Other common functor combinators are in the Data.Functor. namespace in the transformers package.
Existentials with Downcasting
AnyFunctor can also be extended to allow downcasting. Downcasting must be explicitly enabled by adding the Typeable class to whatever you intend to downcast. Every concrete type is an instance of Typeable; type constructors are instances of Typeable1 (1 argument); etc. But it doesn't come for free on type variables, so you need to add class constraints. So the AnyFunctor solution becomes:
{-# LANGUAGE GADTs #-}
import Data.Typeable
data AnyFunctor a where
AnyFunctor :: (Functor f, Typeable1 f) => f a -> AnyFunctor a
instance Functor AnyFunctor where
fmap f (AnyFunctor v) = AnyFunctor (fmap f v)
Which allows downcasting:
downcast :: (Typeable1 f, Typeable a) => AnyFunctor a -> Maybe (f a)
downcast (AnyFunctor f) = cast f
This solution is actually cleaner than I had expected to be, and may be worth pursuing.
One approach is to use existentials:
{-# LANGUAGE GADTs #-}
data AnyFunctor v where
AnyFunctor :: Functor f => f v -> AnyFunctor v
instance Functor AnyFunctor where
fmap f (AnyFunctor fv) = AnyFunctor (fmap f fv)
The input list you ask for in your question isn't possible as it stands because it's not correctly typed, so some wrapping like AnyFunctor is likely to be necessary however you approach it.
You can make the input list by wrapping each value in the AnyFunctor data constructor:
[AnyFunctor (Just 1), AnyFunctor [1,2,3],
AnyFunctor Nothing, AnyFunctor (Right 4)]
Note that when you use fmap (+1) it's a good idea to use an explicit type signature for the 1 to avoid any problems with numeric overloading, e.g. fmap (+(1::Integer)).
The difficulty with AnyFunctor v as it stands is that you can't actually do much with it - you can't even look at the results because it isn't an instance of Show, let alone extract a value for future use.
It's a little tricky to make it into an instance of Show. If we add a Show (f v) constraint to the AnyFunctor data constructor, then the Functor instance stops working because there's no guarantee it'll produce an instance of Show itself. Instead we need to use a sort of "higher-order" typeclass Show1, as discussed in this answer:
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GADTs #-}
data AnyFunctor v where
AnyFunctor :: (Show1 f, Functor f) => f v -> AnyFunctor v
instance Functor AnyFunctor where
fmap f (AnyFunctor fv) = AnyFunctor (fmap f fv)
data ShowDict a where
ShowDict :: Show a => ShowDict a
class Show1 a where
show1Dict :: ShowDict b -> ShowDict (a b)
instance Show v => Show (AnyFunctor v) where
show (AnyFunctor (v :: f v)) =
case show1Dict ShowDict :: ShowDict (f v) of
ShowDict -> "AnyFunctor (" ++ show v ++ ")"
instance Show1 [] where
show1Dict ShowDict = ShowDict
instance Show1 Maybe where
show1Dict ShowDict = ShowDict
instance Show a => Show1 (Either a) where
show1Dict ShowDict = ShowDict
In ghci this gives the following (I've broken the lines for readability):
*Main> map (fmap (+1)) [AnyFunctor (Just 1), AnyFunctor [1,2,3],
AnyFunctor Nothing, AnyFunctor (Right 4)]
[AnyFunctor (Just 2),AnyFunctor ([2,3,4]),
AnyFunctor (Nothing),AnyFunctor (Right 5)]
The basic idea is to express the idea that a type constructor like Nothing, [] or Either a "preserves" the Show constraint, using the Show1 class to say that Show (f v) is available whenever Show v is available.
The same trick applies with other typeclasses. For example #luqui's answer shows how you can extract values using the Typeable class, which already has a built-in Typeable1 variant. Each type class that you add limits the things that you can put into AnyFunctor, but also means you can do more things with it.
One option would be to create a specific data type for your use case, with the additional advantage of having proper names for things.
Another would be to create a specialized * -> * tuples as:
newtype FTuple4 fa fb fc fd r = FTuple4 (fa r, fb r, fc r, fd r)
deriving (Eq, Ord, Show)
So the tuple is homogeneous in values, but heterogeneous in functors.
Then you can define
instance (Functor fa, Functor fb, Functor fc, Functor fd) =>
Functor (FTuple4 fa fb fc fd) where
fmap f (FTuple4 (a, b, c, d)) =
FTuple4 (fmap f a, fmap f b, fmap f c, fmap f d)
and
main = let ft = FTuple4 (Just 1,
[1,2,3],
Nothing,
Right 4 :: Either String Int)
in print $ fmap (+ 1) ft
With this approach, you can pattern match on the result easily, without losing information about the types of the individual elements, their order etc. And, you can have similar instances for Foldable, Traversable, Applicative etc.
Also you don't need to implement the Functor instance yourself, you can use GHC's deriving extensions, so all you need to write to get all the instances is is just
{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
import Data.Foldable
import Data.Traversable
newtype FTuple4 fa fb fc fd r = FTuple4 (fa r, fb r, fc r, fd r)
deriving (Eq, Ord, Show, Functor, Foldable, Traversable)
And even this can be further automated for arbitrary length using Template Haskell.
The advantage of this approach is mainly in the fact that it just wraps ordinary tuples, so you can seamlessly switch between (,,,) and FTuple4, if you need.
Another alternative, without having your own data type, would be to use nested functor products, since what you're describing is just a product of 4 functors.
import Data.Functor.Product
main = let ft = Pair (Just 1)
(Pair [1,2,3]
(Pair Nothing
(Right 4 :: Either String Int)
))
(Pair a (Pair b (Pair c d))) = fmap (+ 1) ft
in print (a, b, c, d)
This is somewhat verbose, but you can do much better by creating your own functor product using type operators:
{-# LANGUAGE TypeOperators, DeriveFunctor #-}
data (f :*: g) a = f a :*: g a
deriving (Eq, Ord, Show, Functor)
infixl 1 :*:
main = let a :*: b :*: c :*: d = fmap (+ 1) $ Just 1 :*:
[1,2,3] :*:
Nothing :*:
(Right 4 :: Either String Int)
in print (a, b, c, d)
This gets probably as terse and universal as possible.

What does it mean to compose two Functors?

Exercise 5 of the Haskell Typeclassopedia Section 3.2 asks for a proof or counterexample on the statement
The composition of two Functors is also a Functor.
I thought at first that this was talking about composing the fmap methods defined by two separate instances of a Functor, but that doesn't really make sense, since the types wouldn't match up as far as I can tell. For two types f and f', the types of fmap would be fmap :: (a -> b) -> f a -> f b and fmap :: (a -> b) -> f' a -> f' b, and that doesn't really seem composable. So what does it mean to compose two Functors?
A Functor gives two mappings: one on the type level mapping types to types (this is the x in instance Functor x where), and one on the computation level mapping functions to functions (this is the x in fmap = x). You are thinking about composing the computation-level mapping, but should be thinking about composing the type-level mapping; e.g., given
newtype Compose f g x = Compose (f (g x))
can you write
instance (Functor f, Functor g) => Functor (Compose f g)
? If not, why not?
What this is talking about is the composition of type constructors like [] and Maybe, not the composition of functions like fmap. So for example, there are two ways of composing [] and Maybe:
newtype ListOfMabye a = ListOfMaybe [Maybe a]
newtype MaybeOfList a = MaybeOfList (Maybe [a])
The statement that the composition of two Functors is a Functor means that there is a formulaic way of writing a Functor instance for these types:
instance Functor ListOfMaybe where
fmap f (ListOfMaybe x) = ListOfMaybe (fmap (fmap f) x)
instance Functor MaybeOfList where
fmap f (MaybeOfList x) = MaybeOfList (fmap (fmap f) x)
In fact, the Haskell Platform comes with the module Data.Functor.Compose that gives you a Compose type that does this "for free":
import Data.Functor.Compose
newtype Compose f g a = Compose { getCompose :: f (g a) }
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose x) = Compose (fmap (fmap f) x)
Compose is particularly useful with the GeneralizedNewtypeDeriving extension:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype ListOfMaybe a = ListOfMaybe (Compose [] Maybe a)
-- Now we can derive Functor and Applicative instances based on those of Compose
deriving (Functor, Applicative)
Note that the composition of two Applicatives is also an Applicative. Therefore, since [] and Maybe are Applicatives, so is Compose [] Maybe and ListOfMaybe. Composing Applicatives is a really neat technique that's slowly becoming more common these days, as an alternative to monad transformers for cases when you don't need the full power of monads.
The composition of two functions is when you put one function inside another function, such as
round (sqrt 23)
This is the composition of the two functions round and sqrt. Similarly, the composition of two functors is when you put one functor inside another functor, such as
Just [3, 5, 6, 2]
List is a functor, and so is Maybe. You can get some intuition for why their composition also is a functor if you try to figure out what fmap should do to the above value. Of course it should map over the contents of the inner functor!
It really helps to think about the categorical interpretation here, a functor F: C -> D takes objects (values) and morphisms (functions) to objects and morphisms from a category C to objects and morphisms in a category D.
For a second functor G : D -> E the composition of functors G . F : C -> E is just taking the codomain of F fmap transformation to be the domain of the G fmap transformation. In Haskell this is accomplished with a little newtype unwrapping.
import Data.Functor
newtype Comp f g a = Comp { unComp :: f (g a) }
compose :: f (g a) -> Comp f g a
compose = Comp
decompose :: Comp f g a -> f (g a)
decompose = unComp
instance (Functor f, Functor g) => Functor (Comp f g) where
fmap foo = compose . fmap (fmap foo) . decompose

Resources