'Applicative in Haskell for single variable
I recently started learning Haskell and encountered a problem with the idea of Applicative
.
I need to make an implementation for
newtype MyTriple a = MyTriple (a,a,a) deriving Show
as Applicative
instance.
I cannot really understand how exactly am i supposed to do that. As far as i know applicative is mostly used with more than one variable. In this particular example im not sure what should be in that part with <*>
symbol.
Can someone please explain this to me (based on my example or not)?
If it is possible please dont provide a direct answer.
Solution 1:[1]
When writing an instance of a type class in Haskell, there are two things that can guide us to the correct implementation: types and type class laws.
What does the type say?
One remarkable property of the type system used in Haskell (and some other functional languages as well) is that given a sufficiently polymorphic function type, there are surprisingly few ways it can be implemented. The intuition is that since a polymorphic function knows nothing about the types it operates on, there are no interesting operations it can apply to values of these types.
The simplest example is a function of type a -> a
. It must produce a value
of type a
as its output; how can it come up with one? Since Haskell doesn't
provide a way to conjure a value of arbitrary type out of thin air1,
the function must use its input value of type a
. What can it do with it? Since
it's a value of an arbitrary type, the answer is "nothing" - it can only return
it as its result. Thus, the only reasonable function of type a -> a
is the
identity function. A more thorough explanation of this idea and further examples can be found in a famous paper by P. Wadler.
Let's go back to the example at hand. The types of pure
and <*>
in the
Applicative
instance for MyTriple
are
pure :: a -> MyTriple a
(<*>) :: MyTriple (a -> b) <*> MyTriple a -> MyTriple b
In pure
, to construct MyTriple a
, we need a triple of values of type a
.
Since we are given one value of type a
and we have no way of producing any
other (just like in the a -> a
function), the only way to implement it is as
pure x = MyTriple (x, x, x)
Operator <*>
is more interesting. In this case:
MyTriple (f, g, h) <*> MyTriple (x, y, z) = ...
-- f, g, h :: a -> b
-- x, y, z :: a
we are given three functions of type a -> b
and three values of type a
.
To construct MyTriple b
, we need three values of type b
. The only way
to get our hands on the value of type b
is to apply one of f
, g
, h
to
one of x
, y
, z
. There is no unique way to do this; we can pair up
the functions and their arguments in an arbitrary fashion.
It follows that all the possible implementations of <*>
for MyTriple
are of the form
MyTriple (f1, f2, f3) <*> MyTriple (x1, x1, x3) = MyTriple (fi xp, fj xq, fk xr)
for some values of i
, j
, k
and p
, q
, r
between 1 and 3.
From the point of view of the type system, all these are correct.
In general, there may be multiple valid instances of applicative functor for a given type (e.g. list has two: the regular one and ZipList),
so it's not necessarily a problem. That being said, there is one more thing we
need to consider.
Applicative functor laws
The applicative functor laws are the following rules:
- Identity:
pure id <*> v = v
- Composition:
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
- Homomorphism:
pure f <*> pure x = pure (f x)
- Interchange:
u <*> pure y = pure ($y) <*> u
A valid instance of the applicative functor must satisfy all these equations. Note that it is not enforced by the compiler - this responsibility lies with the programmer.
At this point, we need to figure out what additional constraints do the applicative functor laws put on the implementation of operator <*>
for
MyTriple
.
Let's start with the Identity. Using our definitions of pure
and <*>
, the
identity law requires that
MyTriple (x1, x1, x3) = MyTriple (id xp, id xq, id xr) = MyTriple (xp, xq, xr)
The only way for this to hold for all possible values of x
's is
if p = 1
, q = 2
and r = 3
. This narrows down the set of possible definitions
of <*>
to
MyTriple (f1, f2, f3) <*> MyTriple (x1, x1, x3) = MyTriple (fi x1, fj x2, fk x3)
so the components of the right argument of <*>
cannot be permuted.
What about the left argument? The answer to that question is given by the interchange law. We have
MyTriple (f1, f2, f3) <*> pure x = MyTriple (fi x, fj x, fk x)
and by the interchange law this must be equal to
pure ($x) <*> MyTriple (f1, f2, f3) = MyTriple (fp x, fq x, fr x)
since in this case f
functions assume the role of arguments of $x
, that is
($x) f = f x
. Combining these two, we see that
MyTriple (fi x, fj x, fk x) = MyTriple (fp x, fq x, fr x)
and again, the only way for this to hold regardless of f
's and x
is if i = p
, j = q
and k = r
, so i = 1
, j = 2
, k = 3
. The final version of operator <*>
, the only one satisfying the applicative functor laws2,
is thus the simplest and most natural one:
MyTriple (f1, f2, f3) <*> MyTriple (x1, x1, x3) = MyTriple (f1 x1, f2 x2, f3 x3)
1 Apart from undefined
& co.
2 Strictly speaking, we need to check the remaining two laws (composition and homomorphism) before we are done
Solution 2:[2]
I think in terms of liftA2
rather than (<*>)
. (<*>)
is lifted function application
(<*>) = liftA2 ($)
For your type, the applicative performs "element-wise" lifting, meaning n-th element in your result is the combination of the incoming n-th element
type V3 :: Type -> Type
data V3 a = V3 a a a
deriving
stock Functor
instance Applicative V3 where
pure :: forall a. a -> V3 a
pure a = V3 a a a
liftA2 :: forall a b c. (a -> b -> c) -> (V3 a -> V3 b -> V3 c)
liftA2 (·) (V3 a1 a2 a3)
(V3 b1 b2 b3)
= (V3 c1 c2 c3)
where
c1, c2, c3 :: c
c1 = a1 · b1
c2 = a2 · b2
c3 = a3 · b3
Lists of a given length (vectors) are isomorphic to functions
Vec 0 a = (Void -> a)
Vec 1 a = (() -> a)
Vec 2 a = (Bool -> a)
Vec 3 a = (Fin3 -> a)
..
Vec n a = (Fin n -> a)
and their applicative instance follows the element-wise function definition. Functors like MyTriple
and others isomorphic to functions (.. ->)
are called Representable
functors.
instance Applicative ((->) a) where
pure :: b -> (a -> b)
pure = const
liftA2 :: (b1 -> b2 -> b3) -> ((a->b1) -> (a->b2) -> (a->b3))
(liftA2 (·) bs1 bs2) a =
bs1 a · bs2 a
Verify that (->) Fin3
is isomorphic to V3
/MyTriple
with the same Applicative
instance.
Consider what happens when (·)
is instantiated with ($)
.
With base 4.17 you can use Generically1
(from GHC.Generics
) to derive Applicative
:
type V3 :: Type -> Type
data V3 a = V3 a a a
deriving
stock (Functor, Generic1)
deriving Applicative
via Generically1 V3
You can derive Applicative
and Monad
for any Representable functor via Co V3
type V3 :: Type -> Type
data V3 a = V3 a a a
deriving (Functor, Applicative, Monad)
via Co V3
instance Distributive V3 where
distribute :: Functor f => f (V3 a) -> V3 (f a)
distribute = distributeRep
type Fin3 :: Type
data Fin3 = Fin0 | Fin1 | Fin2
instance Representable V3 where
type Rep V3 = Fin3
index :: V3 a -> (Fin3 -> a)
index (V3 a b c) = \case
Fin0 -> a
Fin1 -> b
Fin2 -> c
tabulate :: (Fin3 -> a) -> V3 a
tabulate make = V3 (make Fin0) (make Fin1) (make Fin2)
We would derive Distributive
if it weren't for "role" problems, i.e. we cannot coerce under the argument of the functor f
.
Solution 3:[3]
I'm going to assume that you're not having problem with pure
.
You can play around with MyTriple
and <*>
in GHCi to get a better sense for what you're supposed to do. For example, you can ask about the type of <*>
if you constrain the return type to MyTriple _
:
*Q65326400> :t (<*>) :: _ -> _ -> MyTriple _
<interactive>:1:10: error:
* Found type wildcard `_' standing for `MyTriple (a1 -> w1)'
Where: `a1', `w1' are rigid type variables bound by
the inferred type of
<expression> :: MyTriple (a1 -> w1) -> MyTriple a1 -> MyTriple w1
at <interactive>:1:10-29
To use the inferred type, enable PartialTypeSignatures
* In an expression type signature: _ -> _ -> MyTriple _
In the expression: (<*>) :: _ -> _ -> MyTriple _
...
(More, similar, error messages follow...)
This looks scary, but it actually tells you what the involved types are supposed to be:
MyTriple (a1 -> w1) -> MyTriple a1 -> MyTriple w1
or, if we translate to more 'friendly' type variables:
MyTriple (a -> b) -> MyTriple a -> MyTriple b
So, as @Nearoo has pointed out in the comments, the left-hand side of <*>
should be a MyTriple
value that contains functions of the type a -> b
. These can be three different functions, but they must have compatible types.
The right-hand side should be a MyTriple a
, and the return value a MyTriple b
.
You could, for example, implement an Applicative
instance that behaves like this:
*Q65326400> MyTriple (null, odd . length, elem 'f') <*> MyTriple ("foo", "bar", "baz")
MyTriple (False,True,False)
The left-hand side is a MyTriple (String -> Bool)
value, and the right-hand side is a MyTriple String
.
This isn't the only possible Applicative
instance. I can easily think of a dozen more instances, but they probably wouldn't all be lawful.
The next step, once you've figured out how to implement an instance, is to convince yourself (and possibly others) that the instance obeys the applicative functor laws. That's going to rule out some of those technically possible instances.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | Mark Seemann |