I have learnt about Monoidal being an alternative way to represent Applicative not so long ago. There is an interesting question on Typeclassopedia:
(Tricky) Prove that given your implementations from the first exercise [pure and (<*>) written down using unit and (**) and the other way around], the usual Applicative laws and the Monoidal laws stated above are equivalent.
Here are these classes and laws:
-- A note from https://wiki.haskell.org/Typeclassopedia#Alternative_formulation:
-- In this and the following laws, ≅ refers to isomorphism rather than equality.
-- In particular we consider (x,()) ≅ x ≅ ((),x) and ((x,y),z) ≅ (x,(y,z)).
-- Monoidal.
class Functor f => Monoidal f where
unit :: f ()
(**) :: f a -> f b -> f (a,b)
-- unit ** v ≅ v - Left Identity.
-- u ** unit ≅ u - Right Identity.
-- u ** (v ** w) ≅ (u ** v) ** w - Associativity.
-- Applicative.
class Functor f => Applicative f where
pure :: a -> f a
infixl 4 <*>, ...
(<*>) :: f (a -> b) -> f a -> f b
...
-- pure id <*> v = v - Identity.
-- pure f <*> pure x = pure (f x) - Homomorphism.
-- u <*> pure y = pure ($ y) <*> u - Interchange.
-- u <*> (v <*> w) = pure (.) <*> u <*> v <*> w - Composition.
Writing down combinators using others is no big deal:
unit = pure ()
f ** g = (,) <$> f <*> g = liftA2 (,) f g
pure x = const x <$> unit
f <*> g = uncurry ($) <$> (f ** g)
Here is my understanding of why the laws are telling us the same thing:
u <*> pure y = pure ($ y) <*> u -- Interchange: Applicative law.
The first thing we shall notice is that ($ y) ≅ y (more formally: (y -> a) -> a ≅ y). Having that in mind, Interchange law simply tells us that (a, b) ≅ (b, a).
pure id <*> v = v -- Identity: Applicative law.
I reckon id to be something of a unit itself as it is the only inhabitant of type forall a. a -> a. Therefore, this law gives us the Left Identity:
unit ** v = v -- Left Identity: Monoidal law.
Now we can use that (a, b) ≅ (b, a) to write the Right Identity down:
u ** unit = u -- Right Identity: Monoidal law.
The Composition law:
u <*> (v <*> w) = pure (.) <*> u <*> v <*> w -- Composition: Applicative law.
I reckon this law to tell the same thing as Associativity for Monoidal:
u ** (v ** w) ≅ (u ** v) ** w
That is, (a, (b, c)) ≅ ((a, b), c). Applicative just adds a layer of application.
So, we have covered all of the Monoidal laws. I believe there is no need to do it the other way around as we are going to use the same isomorphisms. But one could have noticed something odd - we did not use the Homomorphism Applicative law:
pure f <*> pure x = pure (f x)
I tried understanding Homomorphism in terms of the Naturality free theorem for Monoidal:
fmap (g *** h) (u ** v) = fmap g u ** fmap h v
But it seems odd as Homomorphism does not deal with side-effects, yet Naturality works with them just fine.
So, I have 3 questions:
Is my reasoning right?
Where does Homomorphism stand in this picture?
How can we understand the Naturality free theorem in terms of Applicative?
Just dumping this here for now... wanted to discuss this but I already spent way to long implementing it: it's a Coq proof script that shows the equivalence in an absolutely waterproof way.
Require Import Coq.Program.Basics.
Require Import Coq.Init.Datatypes.
Require Import Coq.Init.Notations.
Notation "f ∘ g" := (compose f g).
Class Functor (F: Type -> Type) : Type :=
{ fmap : forall {x} {y}, (x->y) -> (F x->F y)
; fmap_id : forall x, #fmap x x id = id
; fmap_compose : forall {x} {y} {z} (f: y->z) (g: x->y)
, fmap (f∘g) = fmap f ∘ fmap g
}.
Lemma fmap_twice {F} `{Functor F} {x} {y} {z} (f: y->z) (g: x->y) (xs: F x)
: fmap (f∘g) xs = fmap f (fmap g xs).
Proof.
rewrite fmap_compose. now compute.
Qed.
Definition parallel {a} {b} {c} {d} (f: a->c) (g: b->d)
: (a*b) -> (c*d) := fun xy => match xy with
| (x,y) => (f x, g y)
end.
Notation "f *** g" := (parallel f g) (at level 40, left associativity).
Definition rassoc {a} {b} {c} : ((a*b)*c) -> (a*(b*c))
:= fun xyz => match xyz with | ((x,y),z) => (x,(y,z)) end.
Definition tt_ {a} (x:a) := (tt, x).
Definition _tt {a} (x:a) := (x, tt).
Class Monoidal F `{Functor F} : Type :=
{ funit : F unit
; fzip : forall {a} {b}, F a -> F b -> F (a*b)
; left_identity : forall {a} (v: F a)
, fzip funit v = fmap tt_ v
; right_identity : forall {a} (v: F a)
, fzip v funit = fmap _tt v
; associativity : forall {a} {b} {c} (u: F a) (v: F b) (w: F c)
, fzip u (fzip v w) = fmap rassoc (fzip (fzip u v) w)
; naturality : forall {a} {b} {c} {d}
(g: a->c) (h: b->d) (u: F a) (v: F b)
, fmap (g***h) (fzip u v) = fzip (fmap g u) (fmap h v)
}.
Notation "u ** v" := (fzip u v) (at level 40, left associativity).
Lemma naturalityL {F} `{Monoidal F} {a} {b} {c}
(f: a->c) (u: F a) (v: F b)
: fmap (f***id) (fzip u v) = fzip (fmap f u) v.
Proof.
assert (v = fmap id v) as ->. { now rewrite fmap_id. }
rewrite <- naturality.
assert (v = fmap id v) as <-. { now rewrite fmap_id. }
now trivial.
Qed.
Lemma naturalityR {F} `{Monoidal F} {a} {b} {c}
(f: b->c) (u: F a) (v: F b)
: fmap (id***f) (fzip u v) = fzip u (fmap f v).
Proof.
assert (u = fmap id u) as ->. { now rewrite fmap_id. }
rewrite <- naturality.
assert (u = fmap id u) as <-. { now rewrite fmap_id. }
now trivial.
Qed.
Definition to {a} {b} (y: a) (f: a->b) := f y.
Class Applicative F `{Functor F} : Type :=
{ pure : forall {a}, a -> F a
; app : forall {a} {b}, F (a->b) -> F a -> F b
; identity : forall {a} (v: F a)
, app (pure id) v = v
; homomorphism : forall {a} {b} (f: a->b) (x: a)
, app (pure f) (pure x) = pure (f x)
; interchange : forall {a} {b} (u: F (a->b)) (y: a)
, app u (pure y) = app (pure (to y)) u
; composition : forall {a} {b} {c}
(u: F (b->c)) (v: F (a->b)) (w: F a)
, app u (app v w) = app (app (app (pure compose) u) v) w
; appFtor : forall {a} {b} (g: a->b) (x: F a)
, fmap g x = app (pure g) x
}.
Notation "fs <*> xs" := (app fs xs) (at level 40, left associativity).
Require Import Coq.Program.Tactics.
Require Import Coq.Logic.FunctionalExtensionality.
Definition apl {a} {b} (fx: (a->b)*a)
:= match fx with |(f,x) => f x end.
Program Instance MonoidalIsApplicative {F} `{Monoidal F}
: Applicative F
:= { pure := fun {a} (x: a) => fmap (const x) funit
; app := fun {a} {b} (fs: F (a->b)) (xs: F a)
=> fmap apl (fzip fs xs) }.
Next Obligation. (* identity *)
rewrite <- naturalityL.
rewrite -> left_identity.
repeat (rewrite <- fmap_twice).
rewrite -> fmap_id.
now compute.
Qed.
Next Obligation. (* homomorphism *)
rewrite <- naturality.
rewrite -> left_identity.
repeat (rewrite <- fmap_twice).
now compute.
Qed.
Next Obligation. (* interchange *)
rewrite <- naturalityL.
rewrite <- naturalityR.
repeat (rewrite <- fmap_twice).
rewrite -> right_identity.
rewrite -> left_identity.
repeat (rewrite <- fmap_twice).
now compute.
Qed.
Next Obligation. (* composition *)
rewrite <- naturalityR.
rewrite -> associativity.
repeat (rewrite <- naturalityL).
rewrite -> left_identity.
repeat (rewrite <- naturalityL).
repeat (rewrite <- fmap_twice).
f_equal. (* This part is just about *)
unfold compose. (* convincing Coq that two *)
apply functional_extensionality. (* functions are equal, it *)
intro x. (* has nothing to do with *)
destruct x as ((btc, atb), a0). (* applicative or monoidal *)
now compute. (* functors, specifically. *)
Qed.
Next Obligation. (* appFtor *)
rewrite <- naturalityL.
rewrite -> left_identity.
repeat (rewrite <- fmap_twice).
now compute.
Qed.
Lemma fmapPure {F} `{Applicative F} {a} {b}
(f: a->b) (x: a) : fmap f (pure x: F a) = pure (f x).
Proof.
rewrite -> appFtor.
now apply homomorphism.
Qed.
Lemma fmapBracket {F} `{Applicative F} {a} {b} {c} {d}
(f: c->d) (g: a->b->c) (xs: F a) (ys: F b)
: fmap f (fmap g xs<*>ys) = fmap (fun x y => f (g x y)) xs <*> ys.
Proof.
repeat (rewrite -> appFtor).
rewrite -> composition.
rewrite -> homomorphism.
rewrite -> composition.
repeat (rewrite -> homomorphism).
now compute.
Qed.
Lemma fmap_both {F} `{Applicative F} {a} {b} {c} {d}
(f: a->c->d) (g: b->c) (xs: F a) (ys: F b)
: fmap f xs <*> fmap g ys = fmap (fun x y => f x (g y)) xs <*> ys.
Proof.
repeat (rewrite -> appFtor).
rewrite -> composition.
repeat (rewrite <- appFtor).
rewrite <- fmap_twice.
rewrite -> interchange.
rewrite -> appFtor.
rewrite -> composition.
repeat (rewrite -> homomorphism).
rewrite <- appFtor.
now compute.
Qed.
Definition tup {a} {b} (x:a) (y:b) : (a*b) := (x,y).
Program Instance ApplicativeIsMonoidal {F} `{Applicative F}
: Monoidal F
:= { funit := pure tt
; fzip := fun {a} {b} (u: F a) (v: F b)
=> fmap tup u <*> v }.
Next Obligation. (* left_identity *)
repeat (rewrite -> appFtor).
rewrite -> homomorphism.
now compute.
Qed.
Next Obligation. (* right_identity *)
repeat (rewrite -> appFtor).
rewrite -> interchange.
rewrite -> composition.
repeat (rewrite -> homomorphism).
now compute.
Qed.
Next Obligation. (* associativity *)
repeat (rewrite -> fmapBracket).
rewrite -> composition.
repeat (rewrite <- appFtor).
rewrite <- fmap_twice.
rewrite -> fmap_both.
now compute.
Qed.
Next Obligation. (* naturality *)
rewrite -> fmap_both.
rewrite <- fmap_twice.
rewrite -> fmapBracket.
now compute.
Qed.
Compiled with Coq 8.9.1.
We have
-- Monoidal.
class Functor f => Monoidal f where
unit :: f ()
(**) :: f a -> f b -> f (a,b)
-- unit ** v ≅ v - Left Identity.
-- u ** unit ≅ u - Right Identity.
-- u ** (v ** w) ≅ (u ** v) ** w - Associativity.
-- Applicative,
class Functor f => Applicative f where
pure :: a -> f a
infixl 4 <*>
(<*>) :: f (a -> b) -> f a -> f b
-- pure id <*> v = v - Identity.
-- pure f <*> pure x = pure (f x) - Homomorphism.
-- u <*> pure y = pure ($ y) <*> u - Interchange.
-- u <*> (v <*> w) = pure (.) <*> u <*> v <*> w - Composition.
Implementation 1. Applicative --> Monoidal
unit = pure ()
xs ** ys = pure (,) <*> xs <*> ys
Implementation 2. Monoidal --> Applicative
pure x = const x <$> unit
fs <*> xs = uncurry ($) <$> (fs ** xs)
Now prove Monoidal Laws given Applicative Laws and Implementation 1:
Left Identity. unit ** v ≅ v
unit ** v = pure () ** v
= pure (,) <*> pure () <*> v
= pure (\x -> (,) () x) <*> v
= pure (\x -> (() , x)) <*> v
= pure (() ,) <*> v
≅ pure id <*> v
= v
Right Identity. u ** unit ≅ u
u ** unit = u ** pure ()
= pure (,) <*> u <*> pure ()
= pure ($ ()) <*> (pure (,) <*> u) -- u <*> pure y = pure ($ y) <*> u
-- u <*> (v <*> w) = pure (.) <*> u <*> v <*> w
= pure (.) <*> pure ($ ()) <*> pure (,) <*> u
= pure ((.) ($ ())) <*> pure (,) <*> u
= pure ((.) ($ ()) (,)) <*> u
= pure (\x -> (.) ($ ()) (,) x) <*> u
= pure (\x -> ($ ()) ((,) x)) <*> u
= pure (\x -> (,) x ()) <*> u
= pure (\x -> (x , ())) <*> u
= pure (, ()) <*> u
≅ pure id <*> u
= u
Associativity. u ** (v ** w) ≅ (u ** v) ** w
u ** (v ** w) = ......
You should be able to continue this. I hope I didn't make any mistakes here, but if I did, correct them.
Following Will Ness's advice:
Here is what we get of Homomorphism (besides the laws spoken of about, I used the law specifying how Applicative should relate to Functor: fmap g x = pure g <*> x.)
pure f <*> pure x =
= uncurry ($) <$> ((,) <$> (pure f) <*> (pure x)) =
= (uncurry ($) .) <$> ((,) <$> (pure f)) <*> (pure x) =
= ((uncurry ($) .) . (,) <$> (pure f)) <*> (pure x) =
= (uncurry ($) . (,) f) <$> (pure x) =
= pure $ (uncurry ($) . (,) f) x =
= pure (f x)
So, I guess both Homorphism and fs <*> xs = uncurry ($) <$> (fs ** xs) enable us to perform application on the level of functors.
Related
I think I've come up with an interesting "zippy" Applicative instance for Free.
data FreeMonad f a = Free (f (FreeMonad f a))
| Return a
instance Functor f => Functor (FreeMonad f) where
fmap f (Return x) = Return (f x)
fmap f (Free xs) = Free (fmap (fmap f) xs)
instance Applicative f => Applicative (FreeMonad f) where
pure = Return
Return f <*> xs = fmap f xs
fs <*> Return x = fmap ($x) fs
Free fs <*> Free xs = Free $ liftA2 (<*>) fs xs
It's sort of a zip-longest strategy. For example, using data Pair r = Pair r r as the functor (so FreeMonad Pair is an externally labelled binary tree):
+---+---+ +---+---+ +-----+-----+
| | | | <*> | |
+--+--+ h x +--+--+ --> +--+--+ +--+--+
| | | | | | | |
f g y z f x g x h y h z
I haven't seen anyone mention this instance before. Does it break any Applicative laws? (It doesn't agree with the usual Monad instance of course, which is "substitutey" rather than "zippy".)
Yes, it looks like this is a lawful Applicative. Weird!
As #JosephSible points out, you can read off the identity, homomorphism and interchange laws immediately from the definitions. The only tricky one is the composition law.
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
There are eight cases to check, so strap in.
One case with three Returns: pure (.) <*> Return f <*> Return g <*> Return z
Follows trivially from associativity of (.).
Three cases with one Free:
pure (.) <*> Free u <*> Return g <*> Return z
Working backwards from Free u <*> (Return g <*> Return z) you get fmap (\f -> f (g z)) (Free u), so this follows from the functor law.
pure (.) <*> Return f <*> Free v <*> Return z
fmap ($z) $ fmap f (Free v)
fmap (\g -> f (g z)) (Free v) -- functor law
fmap (f . ($z)) (Free v)
fmap f (fmap ($z) (Free v)) -- functor law
Return f <$> (Free v <*> Return z) -- RHS of `<*>` (first and second cases)
QED
pure (.) <*> Return f <*> Return g <*> Free w
Reduces immediately to fmap (f . g) (Free w), so follows from the functor law.
Three cases with one Return:
pure (.) <*> Return f <*> Free v <*> Free w
Free $ fmap (<*>) (fmap (fmap (f.)) v) <*> w
Free $ fmap (\y z -> fmap (f.) y <*> z) v <*> w -- functor law
Free $ fmap (\y z -> fmap (.) <*> Return f <*> y <*> z) v <*> w -- definition of fmap, twice
Free $ fmap (\y z -> Return f <*> (y <*> z)) v <*> w -- composition
Free $ fmap (\y z -> fmap f (y <*> z)) v <*> w -- RHS of fmap, definition of liftA2
Free $ fmap (fmap f) $ fmap (<*>) v <*> w -- functor law, eta reduce
fmap f $ Free $ liftA2 (<*>) v w -- RHS of fmap
Return f <*> Free v <*> Free w -- RHS of <*>
QED.
pure (.) <*> Free u <*> Return g <*> Free w
Free ((fmap (fmap ($g))) (fmap (fmap (.)) u)) <*> Free w
Free (fmap (fmap (\f -> f . g) u)) <*> Free w -- functor law, twice
Free $ fmap (<*>) (fmap (fmap (\f -> f . g)) u) <*> w
Free $ fmap (\x z -> fmap (\f -> f . g) x <*> z) u <*> w -- functor law
Free $ fmap (\x z -> pure (.) <*> x <*> Return g <*> z) u <*> w
Free $ fmap (\x z -> x <*> (Return g <*> z)) u <*> w -- composition
Free $ fmap (<*>) u <*> fmap (Return g <*>) w -- https://gist.github.com/benjamin-hodgson/5b36259986055d32adea56d0a7fa688f
Free u <*> fmap g w -- RHS of <*> and fmap
Free u <*> (Return g <*> w)
QED.
pure (.) <*> Free u <*> Free v <*> Return z
Free (fmap (<*>) (fmap (fmap (.)) u) <*> v) <*> Return z
Free (fmap (\x y -> fmap (.) x <*> y) u <*> v) <*> Return z -- functor law
Free $ fmap (fmap ($z)) (fmap (\x y -> fmap (.) x <*> y) u <*> v)
Free $ liftA2 (\x y -> (fmap ($z)) (fmap (.) x <*> y)) u v -- see Lemma, with f = fmap ($z) and g x y = fmap (.) x <*> y
Free $ liftA2 (\x y -> fmap (.) x <*> y <*> Return z) u v -- interchange
Free $ liftA2 (\x y -> x <*> (y <*> Return z)) u v -- composition
Free $ liftA2 (\f g -> f <*> fmap ($z) g) u v -- interchange
Free $ fmap (<*>) u <*> (fmap (fmap ($z)) v) -- https://gist.github.com/benjamin-hodgson/5b36259986055d32adea56d0a7fa688f
Free u <*> Free (fmap (fmap ($z)) v)
Free u <*> (Free v <*> Return z)
QED.
Three Frees: pure (.) <*> Free u <*> Free v <*> Free w
This case only exercises the Free/Free case of <*>, whose right-hand side is identical to that of Compose's <*>. So this one follows from the correctness of Compose's instance.
For the pure (.) <*> Free u <*> Free v <*> Return z case I used a lemma:
Lemma: fmap f (fmap g u <*> v) = liftA2 (\x y -> f (g x y)) u v.
fmap f (fmap g u <*> v)
pure (.) <*> pure f <*> fmap g u <*> v -- composition
fmap (f .) (fmap g u) <*> v -- homomorphism
fmap ((f .) . g) u <*> v -- functor law
liftA2 (\x y -> f (g x y)) u v -- eta expand
QED.
Variously I'm using functor and applicative laws under the induction hypothesis.
This was pretty fun to prove! I'd love to see a formal proof in Coq or Agda (though I suspect the termination/positivity checker might mess it up).
For the sake of completeness, I will use this answer to expand on my comment above:
Though I didn't actually write down the proof, I believe the mixed-Free-and-Return cases of the composition law must hold due to parametricity. I also suspect that should be easier to show using the monoidal presentation.
The monoidal presentation of the Applicative instance here is:
unit = Return ()
Return x *&* v = (x,) <$> v
u *&* Return y = (,y) <$> u
-- I will also piggyback on the `Compose` applicative, as suggested above.
Free u *&* Free v = Free (getCompose (Compose u *&* Compose v))
Under the monoidal presentation, the composition/associativity law is:
(u *&* v) *&* w ~ u *&* (v *&* w)
Now let's consider one of its mixed cases; say, the Free-Return-Free one:
(Free fu *&* Return y) *&* Free fw ~ Free fu *&* (Return y *&* Free fw)
(Free fu *&* Return y) *&* Free fw -- LHS
((,y) <$> Free fu) *&* Free fw
Free fu *&* (Return y *&* Free fw) -- RHS
Free fu *&* ((y,) <$> Free fw)
Let's have a closer look at this left-hand side. (,y) <$> Free fu applies (,y) :: a -> (a, b) to the a values found in Free fu :: FreeMonad f a. Parametricity (or, more specifically, the free theorem for (*&*)) means that it doesn't matter if we do that before or after using (*&*). That means the left-hand side amounts to:
first (,y) <$> (Free fu *&* Free fw)
Analogously, the right-hand side becomes:
second (y,) <$> (Free fu *&* Free fw)
Since first (,y) :: (a, c) -> ((a, b), c) and second (y,) :: (a, c) -> (a, (b, c)) are the same up to reassociation of pairs, we have:
first (,y) <$> (Free fu *&* Free fw) ~ second (y,) <$> (Free fu *&* Free fw)
-- LHS ~ RHS
The other mixed cases can be dealt with analogously. For the rest of the proof, see Benjamin Hodgson's answer.
From the definition of Applicative:
If f is also a Monad, it should satisfy
pure = return
(<*>) = ap
(*>) = (>>)
So this implementation would break the applicative laws that say it must agree with the Monad instance.
That said, there's no reason you couldn't have a newtype wrapper for FreeMonad that didn't have a monad instance, but did have the above applicative instance
newtype Zip f a = Zip { runZip :: FreeMonad f a }
deriving Functor
instance Applicative f => Applicative (Zip f) where -- ...
From learn you a haskell: http://learnyouahaskell.com/for-a-few-monads-more
Monad instance for function is this:
instance Monad ((->) r) where
return x = \_ -> x
h >>= f = \w -> f (h w) w
I am having trouble understanding the output of the following:
import Control.Monad.Instances
addStuff :: Int -> Int
addStuff = do
a <- (*2)
b <- (+10)
return (a+b)
addStuff 3 returns 19. Book says 3 gets passed as parameters to both (*2) and (+10). How?
From h >>= f = \w -> f (h w) w , it seems like (h w) is getting bound to a or b.
So, why 6 is not being passed in (+10)?
My understanding of f here is that when (*2) is h, f is the last 2 lines of addStuff. When (+10) is h, f is the last line (in this case the return statement) of addStuff.
Let us first desugar the do block [Haskell'10 report]:
addStuff = do
a <- (*2)
b <- (+10)
return (a+b)
is equivalent to:
addStuff = (*2) >>= \a -> ((+10) >>= \b -> return (a + b))
The inner bind expression ((+10) >>= \b -> return (a + b)), can thus be converted, with the bind definition to:
\w -> (\b -> return (a + b)) ((+10) w) w
and if we substitute return with const, we thus obtain:
\w -> (const . (a+)) ((+10) w) w
We thus have a function that takes as input w, and then calls const . (a+) on (w+10) and w, so it will ignore the last w. Semantically it is equivalent to:
(a+) . (+10)
So now our addStuf is equivalent to:
addStuff = (*2) >>= \a -> ((a+) . (+10))
and if we now use the definition for the bind operator again, we see:
\w -> (\a -> ((a+) . (+10))) ((*2) w) w
or shorter:
\w -> (\a -> ((a+) . (+10))) (w*2) w
We can now substitue a with (w*2) and obtain:
\w -> ((w*2)+) . (+10)) w
So our addStuf is equivalent to:
addStuff w = (w*2) + (w+10)
or more simple:
addStuff w = 3*w + 10
Haskell do notation is syntactic sugar for a series of >>= bindings; in this case, for something like this:
addStuff = (*2) >>= (\a -> (+10) >>= (\b -> return (a + b)))
Passing the updated argument between the computation steps (which would thus be serving a role of a state) is the job of another monad, namely the State monad.
The function aka Reader monad is simpler than that, does less work:
-- (return x) w = x
-- (h >>= f) w = f (h w) w
(h >>= (\a -> g >>= (\b -> return (f a b)))) w
=
(\a -> g >>= (\b -> return (f a b))) (h w) w
=
(g >>= (\b -> return (f (h w) b))) w
=
(\b -> return (f (h w) b))) (g w) w
=
return (f (h w) (g w)) w
=
f (h w) (g w)
Thus the input argument w is passed unchanged into both (by extension, all) the computation steps. Or in the specific case you ask about,
liftM2 (+) ( *2) ( +10) w
=
(+) (w*2) (w+10)
liftM2 function is equivalent to the do block that you show,
liftM2 f h g =
do {
a <- h ;
b <- g ;
return (f a b) }
=
h >>= (\ a ->
g >>= (\ b -> return (f a b) ))
in any monad.
The Composition Applicative Law is as follows:
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
Here's my attempt at proving the Composition law for the ((->) r) type:
RHS:
u <*> (v <*> w)
u <*> ( \y -> v y (w y) )
\x -> u x ( (\y -> v y (w y)) x )
\x -> u x ( v x (w x)) -- (A)
LHS:
pure (.) <*> u <*> v <*> w
const (.) <*> u <*> v <*> w
(\f -> const (.) f (u f)) <*> v <*> w
(\f -> (.) (u f)) <*> v <*> w
(\g -> (\f -> (.) (u f)) g (v g)) <*> w
\x -> (\g -> (\f -> (.) (u f)) g (v g)) x (w x)
-- Expanding labmda by applying to x
\x -> ((\f -> (.) (u f)) x (v x)) (w x)
\x -> (( (.) (u x)) (v x)) (w x)
\x -> ((u x) . (v x)) (w x) -- (B)
I don't think (A) & (B) are equivalent, so where did I make a mistake? I would appreciate any help or suggestions.
You're almost there. You just need to use the definition of (.), which is
(f . g) x = f (g x)
After substituting that definition in the last line of your LHS calculation, you should have two obviously equal lambdas.
I'm trying to check that the Applicative laws hold for the function type ((->) r), and here's what I have so far:
-- Identiy
pure (id) <*> v = v
-- Starting with the LHS
pure (id) <*> v
const id <*> v
(\x -> const id x (g x))
(\x -> id (g x))
(\x -> g x)
g x
v
-- Homomorphism
pure f <*> pure x = pure (f x)
-- Starting with the LHS
pure f <*> pure x
const f <*> const x
(\y -> const f y (const x y))
(\y -> f (x))
(\_ -> f x)
pure (f x)
Did I perform the steps for the first two laws correctly?
I'm struggling with the interchange & composition laws. For interchange, so far I have the following:
-- Interchange
u <*> pure y = pure ($y) <*> u
-- Starting with the LHS
u <*> pure y
u <*> const y
(\x -> g x (const y x))
(\x -> g x y)
-- I'm not sure how to proceed beyond this point.
I would appreciate any help for the steps to verify the Interchange & Composition applicative laws for the ((->) r) type. For reference, the Composition applicative law is as follows:
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
I think in your "Identity" proof, you should replace g with v everywhere (otherwise what is g and where did it come from?). Similarly, in your "Interchange" proof, things look okay so far, but the g that magically appears should just be u. To continue that proof, you could start reducing the RHS and verify that it also produces \x -> u x y.
Composition is more of the same: plug in the definitions of pure and (<*>) on both sides, then start calculating on both sides. You'll soon come to some bare lambdas that will be easy to prove equivalent.
I'm playing around with formulating Applicative in terms of pure and liftA2 (so that (<*>) = liftA2 id becomes a derived combinator).
I can think of a bunch of candidate laws, but I'm not sure what the minimal set would be.
f <$> pure x = pure (f x)
f <$> liftA2 g x y = liftA2 ((f .) . g) x y
liftA2 f (pure x) y = f x <$> y
liftA2 f x (pure y) = liftA2 (flip f) (pure y) x
liftA2 f (g <$> x) (h <$> y) = liftA2 (\x y -> f (g x) (h y)) x y
...
Based on McBride and Paterson's laws for Monoidal(section 7) I'd suggest the following laws for liftA2 and pure.
left and right identity
liftA2 (\_ y -> y) (pure x) fy = fy
liftA2 (\x _ -> x) fx (pure y) = fx
associativity
liftA2 id (liftA2 (\x y z -> f x y z) fx fy) fz =
liftA2 (flip id) fx (liftA2 (\y z x -> f x y z) fy fz)
naturality
liftA2 (\x y -> o (f x) (g y)) fx fy = liftA2 o (fmap f fx) (fmap g fy)
It isn't immediately apparent that these are sufficient to cover the relationship between fmap and Applicative's pure and liftA2. Let's see if we can prove from the above laws that
fmap f fx = liftA2 id (pure f) fx
We'll start by working on fmap f fx. All of the following are equivalent.
fmap f fx
liftA2 (\x _ -> x) (fmap f fx) ( pure y ) -- by right identity
liftA2 (\x _ -> x) (fmap f fx) ( id (pure y)) -- id x = x by definition
liftA2 (\x _ -> x) (fmap f fx) (fmap id (pure y)) -- fmap id = id (Functor law)
liftA2 (\x y -> (\x _ -> x) (f x) (id y)) fx (pure y) -- by naturality
liftA2 (\x _ -> f x ) fx (pure y) -- apply constant function
At this point we've written fmap in terms of liftA2, pure and any y; fmap is entirely determined by the above laws. The remainder of the as-yet-unproven proof is left by the irresolute author as an exercise for the determined reader.
If you define (<.>) = liftA2 (.) then the laws become very nice:
pure id <.> f = f
f <.> pure id = f
f <.> (g <.> h) = (f <.> g) <.> h
Apparently pure f <.> pure g = pure (f . g) follows for free. I believe this formulation originates with Daniel Mlot.
Per the online book, Learn You A Haskell:Functors, Applicative Functors and Monoids, the Appplicative Functor laws are bellow but reorganized for formatting reasons; however, I am making this post community editable since it would be useful if someone could embed derivations:
identity] v = pure id <*> v
homomorphism] pure (f x) = pure f <*> pure x
interchange] u <*> pure y = pure ($ y) <*> u
composition] u <*> (v <*> w) = pure (.) <*> u <*> v <*> w
Note:
function composition] (.) = (b->c) -> (a->b) -> (a->c)
application operator] $ = (a->b) -> a -> b
Found a treatment on Reddit