Composition of Applicative functions - haskell

I can compose pure functions:
let f x = x + 1
let g x = x + 2
let z = f . g
z 1 == 4
I seem to be able to compose monadic functions also:
let f x = Just (x + 1)
let g x = Just (x + 2)
let z x = f x >>= g
z 1 == Just 4
I think I should be able to treat f and g from the last example as applicatives and compose those also, just not sure how:
let f x = Just (x + 1)
let g x = Just (x + 2)
let z x = f <*> g -- this doesn't work
z 1 == Just 4
Is this doable?
Bonus points, can z x = f x >>= g be written as a point-free function? Something like z = f >>= g?

{-# LANGUAGE TypeOperators #-}
The (type-level) composition of any two applicative functors,
newtype (f :. g) a = Compose { getCompose :: f (g a)) }
is an applicative functor.
instance (Functor f, Functor g) => Functor (f :. g) where
fmap f = Compose . fmap (fmap f) . getCompose
instance (Applicative f, Applicative g) => Applicative (f :. g) where
pure = Compose . pure . pure
Compose fgf <*> Compose fgx = Compose ((<*>) <$> fgf <*> fgx)
Your example is the composition of the Maybe applicative with the "function" or "reader" applicative (->) r.
type ReaderWithMaybe r = ((->) r) :. Maybe
x, y :: ReaderWithMaybe Int Int
x = Compose $ \x -> Just (x + 1)
y = Compose $ \x -> Just (x + 2)
Since ReaderWithMaybe r is an Applicative you can do all the usual Applicative stuff. Here I'm smashing my two values together with +.
ghci> let z = (+) <$> x <*> y
ghci> getCompose z 3
Just 9 -- (3 + 1) + (3 + 2) == 9
Note that x and y both get the same input 3. That's the behaviour of (->) r's Applicative instance. If you want to take the result of f x = Just (x + 1) and feed it into g x = Just (x + 2) (to get something equivalent to h x = Just (x + 3)), well, that's what Monad is for.
Bonus points, can z x = f x >>= g be written as a point-free function? Something like z = f >>= g?
You can easily define Kleisli composition by hand.
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
f >=> g = \x -> f x >>= g
It happens that >=> already exists in the standard library, along with its sister <=<. They are lovingly known as the "fish" operators, and they live in Control.Monad.

Applicative functions aren't
let f x = Just $ x + 1
let g x = Just $ x + 2
, they're
let f = Just $ \x -> x + 1
let g = Just $ \x -> x + 2
. Composition then works like liftA2 (.) f g or (.) <$> f <*> g.

Maybe you will be interested by Kleisli composition of monads:
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c

Related

Grouping parameters

Say I have functions which accept the same parameters and I want to test if their outputs are equivalent for the same input.
f :: a -> b -> c
g :: a -> b -> c
f a b == g a b
How can I package the parameters a and b in x so I can write the following instead.
f x == g x
What are the best ways to accomplish this without needing to wrap the functions themselves?
The only way to do exactly what you’re asking is to use uncurry:
let
x = (a, b)
in uncurry f x == uncurry g x
(Or uncurryN for N arguments.)
However, instead of packaging the arguments in a tuple, you could use the (->) x instance of Applicative (i.e., functions taking x as input) to implicitly “spread” the arguments to the parameters of both functions, so at least you only have to mention them once. This instance is commonly used in point-free code.
For example, using liftA2 specialised to this instance:
-- General type:
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
-- Specialised to ‘(->) x’ (using TypeApplications syntax):
liftA2 #((->) _) :: (a -> b -> c) -> (x -> a) -> (x -> b) -> (x -> c)
You get this pattern:
liftA2 h f g x
-- =
(h <$> f <*> g) x
-- =
h (f x) (g x)
To lift more arguments, you add another liftA2 or … <$> … <*> …:
liftA2 (liftA2 h) f g x y
-- =
(liftA2 h <$> f <*> g) x y
-- =
h (f x y) (g x y)
So in a case like yours:
f, g :: Int -> Char -> Bool
f i c = chr i == c
g i c = i == ord c
(liftA2 . liftA2) (==) f g :: Int -> Char -> Bool
-- =
liftA2 (liftA2 (==)) f g
-- =
(\ x y -> f x y == g x y)
The N in liftAN corresponds to the number of functions; the number of liftAN calls corresponds to the number of arguments.

A traversal as data

I heard about this construction which is loosely described as “a traversal represented in data, applied to some structure, without the need for the applicative”
It can be defined as:
data X a b r =
| Done r
| Step a (X a b (b -> r))
A word description would be as follows:
the type X a b r describes the shape of a structure
which contains things of type a
and for each a you get the opportunity to produce something of type b
and provided you do that for each a,
you get something of type r.
Thus a “traversal” of a list, [a], has type X a b [b], because if you can turn each a of the list into a b then you get a [b].
My question is: what is this thing called? Is there a reference to more information about it?
Example usage:
instance Functor (X a b) where
fmap f (Done r) = f r
fmap f (Step a next) = Step a (fmap (f .) next)
f :: [a] -> X a b [b]
f [] = Done []
f (a:as) = Step a (fmap (flip (:)) as)
g :: Applicative f => (a -> f b) -> X a b r -> f r
g f (Done r) = pure r
g f (Step a next) = g f next <*> f a
More generally:
instance Applicative (X a b) where
pure x = Done x
Done f <*> y = fmap (\y -> f y) y
Step a next <*> y = Step a (fmap flip next <*> y)
t :: Traversable t => t a -> X a b (t b)
t = traverse (\a -> Step a (Done id))
And, assuming I haven’t made any errors, we should find that:
flip g . t == traverse
Edit: I’ve thought about this some more. There is something this doesn’t have which a traversal has: a traversal can split up the computation into something that isn’t “one at a time,” for example to traverse a binary tree one can traverse the left and right half “in parallel.” Here is a structure that I think gives the same effect:
data Y a b r =
| Done r
| One a (b -> r)
| forall s t. Split (Y a b s) (Y a b t) (s -> t -> r)
(Slightly vague syntax as I don’t remember it and don’t want to write this as a gadt)
f1 :: X a b r -> Y a b r
f1 (Done x) = Done x
f1 (Step a next) = Split (One a id) (f1 next) (flip ($))
f2 :: Y a b r -> X a b r
f2 (Done x) = Done x
f2 (One a f) = Step a (Done f)
f2 (Split x y f) = f <$> f2 x <*> f2 y

how to prove the associative law of the compositon operation (.) in Haskell

say ,
f :: a -> b
g :: b -> c
h :: c -> d
why the equation
h.(g.f) = (h.g).f
is right?
how to prove it?
and the composition operation is just a basic operation in Haskell,
or we can get one by ourselves? if so how to achieve it?
You can define the composition operator yourself as follows:
(.) :: (b -> c) -> (a -> b) -> a -> c
g . f = \x -> g (f x)
Now, to prove associativity:
lhs = h . (g . f)
= \x -> h ((g . f) x) -- substitution
= \x -> h ((\y -> g (f y)) x) -- substitution
= \x -> h (g (f x)) -- beta reduction
rhs = (h . g) . f
= \x -> (h . g) (f x) -- substitution
= \x -> (\y -> h (g y)) (f x) -- substitution
= \x -> h (g (f x)) -- beta reduction
Now, we have lhs = rhs. QED.

Haskell: Why is ((.).(.)) f g equal to f . g x?

Could you please explain the meaning of the expression ((.).(.))?
As far as I know (.) has the type (b -> c) -> (a -> b) -> a -> c.
(.) . (.) is the composition of the composition operator with itself.
If we look at
((.) . (.)) f g x
we can evaluate that a few steps, first we parenthesise,
((((.) . (.)) f) g) x
then we apply, using (foo . bar) arg = foo (bar arg):
~> (((.) ((.) f)) g) x
~> (((.) f) . g) x
~> ((.) f) (g x)
~> f . g x
More principled,
(.) :: (b -> c) -> (a -> b) -> (a -> c)
So, using (.) as the first argument of (.), we must unify
b -> c
with
(v -> w) -> (u -> v) -> (u -> w)
That yields
b = v -> w
c = (u -> v) -> (u -> w)
and
(.) (.) = ((.) .) :: (a -> v -> w) -> a -> (u -> v) -> (u -> w)
Now, to apply that to (.), we must unify the type
a -> v -> w
with the type of (.), after renaming
(s -> t) -> (r -> s) -> (r -> t)
which yields
a = s -> t
v = r -> s
w = r -> t
and thus
(.) . (.) :: (s -> t) -> (u -> r -> s) -> (u -> r -> t)
and from the type we can (almost) read that (.) . (.) applies a function (of one argument) to the result of a function of two arguments.
You've got an answer already, here's a slightly different take on it.
In combinatory logic (.) is B-combinator : Babc = a(bc). When writing combinator expressions it is customary to assume that every identifier consists of one letter only, and omit white-space in application, to make the expressions more readable. Of course the usual currying applies: abcde is (((ab)c)d)e and vice versa.
(.) is B, so ((.) . (.)) == (.) (.) (.) == BBB. So,
BBBfgxy = B(Bf)gxy = (Bf)(gx)y = Bf(gx)y = (f . g x) y
abc a bc a b c
We can throw away both ys at the end (this is known as eta-reduction: Gy=Hy --> G=H, if y does not appear inside H1). But also, another way to present this, is
BBBfgxy = B(Bf)gxy = ((f .) . g) x y = f (g x y) -- (.) f == (f .)
-- compare with: (f .) g x = f (g x)
((f .) . g) x y might be easier to type in than ((.).(.)) f g x y, but YMMV.
1 For example, with S combinator, defined as Sfgx = fx(gx), without regard for that rule we could write
Sfgx = fx(gx) = B(fx)gx = (f x . g) x
Sfg = B(fx)g = (f x . g) --- WRONG, what is "x"?
which is nonsense.

What is a general scheme for writing a function in pointfree style?

I am working through the 20 Intermediate Haskell Exercises at the moment, which is quite a fun exercise. It involves implementing various instances of the typeclasses Functor and Monad (and functions that takes Functors and Monads as arguments) but with cute names like Furry and Misty to disguise what we're doing (makes for some interesting code).
I've been trying to do some of this in a point-free style, and I wondered if there's a general scheme for turning a point-ful (?) definition into a point-free definition. For example, here is the typeclass for Misty:
class Misty m where
unicorn :: a -> m a
banana :: (a -> m b) -> m a -> m b
(the functions unicorn and banana are return and >>=, in case it's not obvious) and here's my implementation of apple (equivalent to flip ap):
apple :: (Misty m) => m a -> m (a -> b) -> m b
apple x f = banana (\g -> banana (unicorn . g) x) f
Later parts of the exercises have you implement versions of liftM, liftM2 etc. Here are my solutions:
appleTurnover :: (Misty m) => m (a -> b) -> m a -> m b
appleTurnover = flip apple
banana1 :: (Misty m) => (a -> b) -> m a -> m b
banana1 = appleTurnover . unicorn
banana2 :: (Misty m) => (a -> b -> c) -> m a -> m b -> m c
banana2 f = appleTurnover . banana1 f
banana3 :: (Misty m) => (a -> b -> c -> d) -> m a -> m b -> m c -> m d
banana3 f x = appleTurnover . banana2 f x
banana4 :: (Misty m) => (a -> b -> c -> d -> e) -> m a -> m b -> m c -> m d -> m e
banana4 f x y = appleTurnover . banana3 f x y
Now, banana1 (equivalent to liftM or fmap) I was able to implement in pointfree style, by a suitable definition of appleTurnover. But with the other three functions I've had to use parameters.
My question is: is there a recipe for turning definitions like these into point-free definitions?
As demonstrated by the pointfree utility, it's possible to do any such conversion automatically. However, the result is more often obfuscated than improved. If one's goal is to enhance legibility rather than destroy it, then the first goal should be to identify why an expression has a particular structure, find a suitable abstraction, and build things up that way.
The simplest structure is simply chaining things together in a linear pipeline, which is plain function composition. This gets us pretty far just on its own, but as you noticed it doesn't handle everything.
One generalization is to functions with additional arguments, which can be built up incrementally. Here's one example: Define onResult = (. (.)). Now, applying onResult n times to an initial value of id gives you function composition with the result of an n-ary function. So we can define comp2 = onResult (.), and then write comp2 not (&&) to define a NAND operation.
Another generalization--which encompasses the above, really--is to define operators that apply a function to a component of a larger value. An example here would be first and second in Control.Arrow, which work on 2-tuples. Conal Elliott's Semantic Editor Combinators are based on this approach.
A slightly different case is when you have a multi-argument function on some type b, and a function a -> b, and need to combine them into a multi-argument function using a. For the common case of 2-ary functions, the module Data.Function provides the on combinator, which you can use to write expressions like compare `on` fst to compare 2-tuples on their first elements.
It's a trickier issue when a single argument is used more than once, but there are meaningful recurring patterns here that can also be extracted. A common case here is applying multiple functions to a single argument, then collecting the results with another function. This happens to correspond to the Applicative instance for functions, which lets us write expressions like (&&) <$> (> 3) <*> (< 9) to check if a number falls in a given range.
The important thing, if you want to use any of this in actual code, is to think about what the expression means and how that's reflected in the structure. If you do that, and then refactor it into pointfree style using meaningful combinators, you'll often make the intent of the code clearer than it would otherwise be, unlike the typical output of pointfree.
Yes! One of the tricks is to write your dots in prefix notation rather than infix. Then you should be able to find new things that look like function composition. Here's an example:
banana2 f = appleTurnover . banana1 f
= (.) appleTurnover (banana1 f)
= ((.) appleTurnOver) . banana1 $ f
banana2 = (appleTurnover .) . banana1
The source code for the pointfree utility contains more, but this one handles a lot of cases.
banana4 f x y = appleTurnover . banana3 f x y
= (.) appleTurnover ((banana3 f x) y)
= ((.) appleTurnover) . (banana3 f x) $ y
banana4 f x = ((.) appleTurnover) . (banana3 f x)
= (.) ((.) appleTurnover) (banana3 f x)
= ((.) ((.) appleTurnover)) ((banana3 f) x)
= ((.) ((.) appleTurnover)) . (banana3 f) $ x
banana4 f = ((.) ((.) appleTurnover)) . (banana3 f)
= (.) ((.) ((.) appleTurnover)) (banana3 f)
= ((.) ((.) ((.) appleTurnover))) (banana3 f)
= ((.) ((.) ((.) appleTurnover))) . banana3 $ f
banana4 = ((.) ((.) ((.) appleTurnover))) . banana3
= (((appleTurnover .) .) .) . banana3
I use the following term rewrite system:
\x -> f x ------> f
f y x ----------> flip f x y
\x -> f (g x) --> f . g
It is incomplete (read why in books about combinatory logic), but it's enough:
Here is banana2:
banana2 f = appleTurnover . banana1 f
Rewrite as a lambda:
banana2 = \f -> appleTurnover . banana1 f
Write (.) in prefix style:
banana2 = \f -> (.) appleTurnover (banana1 f)
Note that
banana2 = \f -> ((.) appleTurnover) (banana1 f)
So rule 3 can be applied. f is (.) appleTurnover and g is banana:
banana2 = ((.) appleTurnover) . banana1
There is a pointfree package which takes a Haskell function definition and attempts to re-write it in a pointfree style. I'd suggest experimenting with it to get new ideas. See this page for more details; the package is available here.
Since pointfree style is combinators style, just apply known combinators definitions, reading them backwards to make the substitution:
B f g x = f (g x) -- (.) , <$> for ((->) a)
C f x y = f y x -- flip
K x y = x -- const
I x = x -- id
S f g x = f x (g x) -- <*> , ap for ((->) a)
W f x = f x x -- join
(f >>= g) x = g (f x) x
(f =<< g) x = f (g x) x
At times liftMx, liftAx, sequence, sequenceA can simplify things. I'd also consider foldr, unfoldr, iterate, until etc. as basic combinators.
Often, using operator sections helps too:
op a b = (a `op` b) = (`op` b) a = (a `op`) b
Some patterns can become familiar and so, used directly:
((f .) . g) x y = f (g x y)
((. f) . g) x y = g x (f y)
(((f .) .) . g) x y z = (f .) (g x y) z = f (g x y z)
(((. f) .) . g) x y z = (. f) (g x y) z = g x y (f z)
etc.

Resources