What does <*> do in addRecip x y = fmap (+) (recipMay x) <*> recipMay y? - haskell

addRecip :: Double -> Double -> Maybe Double
addRecip x y = fmap (+) (recipMay x) <*> recipMay y
where
recipMay a | a == 0 = Nothing
| otherwise = Just (1 / a)
I look up some explanation for <*>.
<*> takes a functor that contains a function taking an a and returning a b, and a functor that contains an a, and it returns a functor that contains a b. So <*> kind of extract the function from a functor and applies it to an arguments also inside a functor, and finally returns the result into a functor
This is an example:
fs <*> xs = [f x | f <- fs, x <- xs]
But in my case, it seems a bit different. The elements in recipMay x are not functions.

<*> Applies an applicative value to another. It's a richer counterpart to regular function application. The applicative values are decorated in some way, for example, it can be optional whether there's any value as you would perceive it (for Maybe, which is your case), or there can be very many values (for List).
The application of one applicative value to the other therefore has some special behaviour. For lists, a <*> b applies each member of a to each member of b making a huge list of all combinations whilst for Maybe (which is your case) a <*> b gives Just (a' b') if a and b are (Just a') and (Just b') and gives Nothing if either or both a and b are Nothing - for Maybe, in summary, it's function application for optional values where the result is absent if any value involved is absent.
There are some rules to how <*> is implemented which means that you can always view this as [apply a "contained function" to a "contained value"] and as long as you do all your work in the contained domain (using <$>, <*>, pure, >>=, <|>, etc) then you can think of it as the same as regular function application, but when you come to "extract" values you get to see the added richness.

The (<*>) :: Applicative f => f (a -> b) -> f a -> f b comes from the Applicative typeclass. An Applicative is a (quoting the documentation) "A functor with application.". You can think of a Functor as a collection (although there are other types that are no collections that are functors, like a function for example).
If we see a functor as a collection then the (<*>) operator thus takes two of these collections. The first collection stores functions of type a -> b, and the latter is a collection of bs. The result is then a collection (the same type of collection) of bs, by applying every element in the second collection to every function in the first collection.
So for a list it looks like:
(<*>) :: [a -> b] -> [a] -> [b]
(<*>) fs xs = [fi xj | fi <- fs, xj <- xs]
A Maybe is also some sort of collection: it either contains no elements (the Nothing case), or one element (the Just x case with x the element). You can thus see a Maybe as a collection with "multiplicity" 0..1.
In case one of the two operands is a Nothing (or both), then the result is a Nothing as well, since if there is no function, or no element, there is no "result" of a function application. Only in case both operands are Justs (so Just f and Just x), we can perform function application (so Just (f x)):
(<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
(<*>) (Just f) (Just x) = Just (f x)
(<*>) _ _ = Nothing
In this specific case, we can analyze the use:
addRecip :: Double -> Double -> Maybe Double
addRecip x y = (fmap (+) (recipMay x)) <*> recipMay y
where
recipMay a | a == 0 = Nothing
| otherwise = Just (1 / a)
We thus see two operands: fmap (+) (RecipMay x) and recipMay y. In case x and/or y are 0, then the operands are respectively Nothing. Since in that case the corresponding recipMay is Nothing.
We thus could write it like:
addRecip :: Double -> Double -> Maybe Double
addRecip x y | x == 0 = Nothing
| y == 0 = Nothing
| otherwise = Just ((1/x) + (1/y))
But in the above we thus repeat the == 0, and 1/ logic twice.

Here the functor is Maybe. That <*> will return Nothing if either argument is Nothing (i.e., it involved a division by zero)
Nothing <*> _ = Nothing
_ <*> Nothing = Nothing
In the remaining case, it just applies the wrapped function:
Just f <*> Just x = Just (f x)
Also note that
fmap (+) (recipMay x) <*> recipMay y
is a slightly unusual notation. Usually that's written as
(+) <$> recipMay x <*> recipMay y
which is completely equivalent, since fmap is written as the infix <$>, but arguably more readable.
Here, fmap (+) (recipMay x) (or (+) <$> recipMay x) means
if x == 0
then Nothing
else Just (\a -> 1/x + a)

Related

Applicative functor evaluation is not clear to me

I am currently reading Learn You a Haskell for Great Good! and am stumbling on the explanation for the evaluation of a certain code block. I've read the explanations several times and am starting to doubt if even the author understands what this piece of code is doing.
ghci> (+) <$> (+3) <*> (*100) $ 5
508
An applicative functor applies a function in some context to a value in some context to get some result in some context. I have spent a few hours studying this code block and have come up with a few explanations for how this expression is evaluated, and none of them are satisfactory. I understand that (5+3)+(5*100) is 508, but the problem is getting to this expression. Does anyone have a clear explanation for this piece of code?
The other two answers have given the detail of how this is calculated - but I thought I might chime in with a more "intuitive" answer to explain how, without going through a detailed calculation, one can "see" that the result must be 508.
As you implied, every Applicative (in fact, even every Functor) can be viewed as a particular kind of "context" which holds values of a given type. As simple examples:
Maybe a is a context in which a value of type a might exist, but might not (usually the result of a computation which may fail for some reason)
[a] is a context which can hold zero or more values of type a, with no upper limit on the number - representing all possible outcomes of a particular computation
IO a is a context in which a value of type a is available as a result of interacting with "the outside world" in some way. (OK that one isn't so simple...)
And, relevant to this example:
r -> a is a context in which a value of type a is available, but its particular value is not yet known, because it depends on some (as yet unknown) value of type r.
The Applicative methods can be very well understood on the basis of values in such contexts. pure embeds an "ordinary value" in a "default context" in which it behaves as closely as possible in that context to a "context-free" one. I won't go through this for each of the 4 examples above (most of them are very obvious), but I will note that for functions, pure = const - that is, a "pure value" a is represented by the function which always produces a no matter what the source value.
Rather than dwell on how <*> can best be described using the "context" metaphor though, I want to dwell on the particular expression:
f <$> a <*> b
where f is a function between 2 "pure values" and a and b are "values in a context". This expression in fact has a synonym as a function: liftA2. Although using the liftA2 function is generally considered less idiomatic than the "applicative style" using <$> and <*>, the name emphasies that the idea is to "lift" a function on "ordinary values" to one on "values in a context". And when thought of like this, I think it is usually very intuitive what this does, given a particular "context" (ie. a particular Applicative instance).
So the expression:
(+) <$> a <*> b
for values a and b of type say f Int for an Applicative f, behaves as follows for different instances f:
if f = Maybe, then the result, if a and b are both Just values, is to add up the underlying values and wrap them in a Just. If either a or b is Nothing, then the whole expression is Nothing.
if f = [] (the list instance) then the above expression is a list containing all sums of the form a' + b' where a' is in a and b' is in b.
if f = IO, then the above expression is an IO action that performs all the I/O effects of a followed by those of b, and results in the sum of the Ints produced by those two actions.
So what, finally, does it do if f is the function instance? Since a and b are both functions describing how to get a given Int given an arbitrary (Int) input, it is natural that lifting the (+) function over them should be the function that, given an input, gets the result of both the a and b functions, and then adds the results.
And that is, of course, what it does - and the explicit route by which it does that has been very ably mapped out by the other answers. But the reason why it works out like that - indeed, the very reason we have the instance that f <*> g = \x -> f x (g x), which might otherwise seem rather arbitrary (although in actual fact it's one of the very few things, if not the only thing, that will type-check), is so that the instance matches the semantics of "values which depend on some as-yet-unknown other value, according to the given function". And in general, I would say it's often better to think "at a high level" like this than to be forced to go down to the low-level details of exactly how computations are performed. (Although I certainly don't want to downplay the importance of also being able to do the latter.)
[Actually, from a philosophical point of view, it might be more accurate to say that the definition is as it is just because it's the "natural" definition that type-checks, and that it's just happy coincidence that the instance then takes on such a nice "meaning". Mathematics is of course full of just such happy "coincidences" which turn out to have very deep reasons behind them.]
It is using the applicative instance for functions. Your code
(+) <$> (+3) <*> (*100) $ 5
is evaluated as
( (\a->\b->a+b) <$> (\c->c+3) <*> (\d->d*100) ) 5 -- f <$> g
( (\x -> (\a->\b->a+b) ((\c->c+3) x)) <*> (\d->d*100) ) 5 -- \x -> f (g x)
( (\x -> (\a->\b->a+b) (x+3)) <*> (\d->d*100) ) 5
( (\x -> \b -> (x+3)+b) <*> (\d->d*100) ) 5
( (\x->\b->(x+3)+b) <*> (\d->d*100) ) 5 -- f <*> g
(\y -> ((\x->\b->(x+3)+b) y) ((\d->d*100) y)) 5 -- \y -> (f y) (g y)
(\y -> (\b->(y+3)+b) (y*100)) 5
(\y -> (y+3)+(y*100)) 5
(5+3)+(5*100)
where <$> is fmap or just function composition ., and <*> is ap if you know how it behaves on monads.
Let us first take a look how fmap and (<*>) are defined for a function:
instance Functor ((->) r) where
fmap = (.)
instance Applicative ((->) a) where
pure = const
(<*>) f g x = f x (g x)
liftA2 q f g x = q (f x) (g x)
The expression we aim to evaluate is:
(+) <$> (+3) <*> (*100) $ 5
or more verbose:
((+) <$> (+3)) <*> (*100) $ 5
If we thus evaluate (<$>), which is an infix synonym for fmap, we thus see that this is equal to:
(+) . (+3)
so that means our expression is equivalent to:
((+) . (+3)) <*> (*100) $ 5
Next we can apply the sequential application. Here f is thus equal to (+) . (+3) and g is (*100). This thus means that we construct a function that looks like:
\x -> ((+) . (+3)) x ((*100) x)
We can now simplify this and rewrite this into:
\x -> ((+) (x+3)) ((*100) x)
and then rewrite it to:
\x -> (+) (x+3) ((*100) x)
We thus have constructed a function that looks like:
\x -> (x+3) + 100 * x
or simpler:
\x -> 101 * x + 3
If we then calculate:
(\x -> 101*x + 3) 5
then we of course obtain:
101 * 5 + 3
and thus:
505 + 3
which is the expected:
508
For any applicative,
a <$> b <*> c = liftA2 a b c
For functions,
liftA2 a b c x
= a (b x) (c x) -- by definition;
= (a . b) x (c x)
= ((a <$> b) <*> c) x
Thus
(+) <$> (+3) <*> (*100) $ 5
=
liftA2 (+) (+3) (*100) 5
=
(+) ((+3) 5) ((*100) 5)
=
(5+3) + (5*100)
(the long version of this answer follows.)
Pure math has no time. Pure Haskell has no time. Speaking in verbs ("applicative functor applies" etc.) can be confusing ("applies... when?...").
Instead, (<*>) is a combinator which combines a "computation" (denoted by an applicative functor) carrying a function (in the context of that type of computations) and a "computation" of the same type, carrying a value (in like context), into one combined "computation" that carries out the application of that function to that value (in such context).
"Computation" is used to contrast it with a pure Haskell "calculations" (after Philip Wadler's "Calculating is better than Scheming" paper, itself referring to David Turner's Kent Recursive Calculator language, one of predecessors of Miranda, the (main) predecessor of Haskell).
"Computations" might or might not be pure themselves, that's an orthogonal issue. But mainly what it means, is that "computations" embody a generalized function call protocol. They might "do" something in addition to / as part of / carrying out the application of a function to its argument. Or in types,
( $ ) :: (a -> b) -> a -> b
(<$>) :: (a -> b) -> f a -> f b
(<*>) :: f (a -> b) -> f a -> f b
(=<<) :: (a -> f b) -> f a -> f b
With functions, the context is application (another one), and to recover the value -- be it a function or an argument -- the application to a common argument is to be performed.
(bear with me, we're almost there).
The pattern a <$> b <*> c is also expressible as liftA2 a b c. And so, the "functions" applicative functor "computation" type is defined by
liftA2 h x y s = let x' = x s -- embellished application of h to x and y
y' = y s in -- in context of functions, or Reader
h x' y'
-- liftA2 h x y = let x' = x -- non-embellished application, or Identity
-- y' = y in
-- h x' y'
-- liftA2 h x y s = let (x',s') = x s -- embellished application of h to x and y
-- (y',s'') = y s' in -- in context of
-- (h x' y', s'') -- state-passing computations, or State
-- liftA2 h x y = let (x',w) = x -- embellished application of h to x and y
-- (y',w') = y in -- in context of
-- (h x' y', w++w') -- logging computations, or Writer
-- liftA2 h x y = [h x' y' | -- embellished application of h to x and y
-- x' <- x, -- in context of
-- y' <- y ] -- nondeterministic computations, or List
-- ( and for Monads we define `liftBind h x k =` and replace `y` with `k x'`
-- in the bodies of the above combinators; then liftA2 becomes liftBind: )
-- liftA2 :: (a -> b -> c) -> f a -> f b -> f c
-- liftBind :: (a -> b -> c) -> f a -> (a -> f b) -> f c
-- (>>=) = liftBind (\a b -> b) :: f a -> (a -> f b) -> f b
And in fact all the above snippets can be just written with ApplicativeDo as liftA2 h x y = do { x' <- x ; y' <- y ; pure (h x' y') } or even more intuitively as
liftA2 h x y = [h x' y' | x' <- x, y' <- y], with Monad Comprehensions, since all the above computation types are monads as well as applicative functors. This shows by the way that (<*>) = liftA2 ($), which one might find illuminating as well.
Indeed,
> :t let liftA2 h x y r = h (x r) (y r) in liftA2
:: (a -> b -> c) -> (t -> a) -> (t -> b) -> (t -> c)
> :t liftA2 -- the built-in one
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
i.e. the types match when we take f a ~ (t -> a) ~ (->) t a, i.e. f ~ (->) t.
And so, we're already there:
(+) <$> (+3) <*> (*100) $ 5
=
liftA2 (+) (+3) (*100) 5
=
(+) ((+3) 5) ((*100) 5)
=
(+) (5+3) (5*100)
=
(5+3) + (5*100)
It's just how liftA2 is defined for this type, Applicative ((->) t) => ...:
instance Applicative ((->) t) where
pure x t = x
liftA2 h x y t = h (x t) (y t)
There's no need to define (<*>). The source code says:
Minimal complete definition
pure, ((<*>) | liftA2)
So now you've been wanting to ask for a long time, why is it that a <$> b <*> c is equivalent to liftA2 a b c?
The short answer is, it just is. One can be defined in terms of the other -- i.e. (<*>) can be defined via liftA2,
g <*> x = liftA2 id g x -- i.e. (<*>) = liftA2 id = liftA2 ($)
-- (g <*> x) t = liftA2 id g x t
-- = id (g t) (x t)
-- = (id . g) t (x t) -- = (id <$> g <*> x) t
-- = g t (x t)
(which is exactly as it is defined in the source),
and it is a law that every Applicative Functor must follow, that h <$> g = pure h <*> g.
Lastly,
liftA2 h g x == pure h <*> g <*> x
-- h g x == (h g) x
because <*> associates to the left: it is infixl 4 <*>.

Why can't I implement these functions with a Functor/Applicative constraint only?

Consider the following functions, taken from the answers to this problem set:
func6 :: Monad f => f Integer -> f (Integer,Integer)
func6 xs = do
x <- xs
return $ if x > 0 then (x, 0)
else (0, x)
func6' :: Functor f => f Integer -> f (Integer,Integer)
-- slightly unorthodox idiom, with an partially applied fmap
func6' = fmap $ \x -> if x > 0 then (x,0) else (0,x)
-- func7 cannot be implemented without Monad if we care about the precise
-- evaluation and layzness behaviour:
-- > isJust (func7 (Just undefined))
-- *** Exception: Prelude.undefined
--
-- If we care not, then it is equivalent to func6, and there we can. Note that
-- > isJust (func6 (Just undefined))
-- True
func7 :: Monad f => f Integer -> f (Integer,Integer)
func7 xs = do
x <- xs
if x > 0 then return (x, 0)
else return (0, x)
-- func9 cannot be implemented without Monad: The structure of the computation
-- depends on the result of the first argument.
func9 :: Monad f => f Integer -> f Integer -> f Integer -> f Integer
func9 xs ys zs = xs >>= \x -> if even x then ys else zs
Although I understand the counterexample for func7, I don't understand the given reasoning for why we can implement func7 and func9 using monads only. How do monad/applicative/functor laws fit with the above reasoning?
I don't think typeclass laws are what you need to be worrying about here; in fact, I think the typeclasses unnnecessarily complicate the exercise, if your purpose is to understand nonstrictness.
Here's a simpler example where everything is monomorphic, and rather than give examples using bottom, we're going to use :sprint in GHCi to watch the extent of the evaluation.
func6
My x6 example here corresponds to func6 in the question.
λ> x6 = Just . bool 'a' 'b' =<< Just True
Initially, nothing has been evaluated.
λ> :sprint x6
x6 = _
Now we evaluate 'isJust x6'.
λ> isJust x6
True
And now we can see that x6 has been partially evaluated. Only to its head, though.
λ> :sprint x6
y = Just _
Why? Because there was no need to know the result of the bool 'a' 'b' part just to determine whether the Maybe was going to be a Just. So it remains an unevaluated thunk.
func7
My x7 example here corresponds to func7 in the question.
λ> x7 = bool (Just 'a') (Just 'b') =<< Just True
x :: Maybe Char
Again, initially nothing is evaluated.
λ> :sprint x7
x = _
And again we'll apply isJust.
λ> isJust x7
True
In this case, the content of the Just did get evaluated (so we say this definition was "more strict" or "not as lazy").
λ> :sprint x7
x = Just 'b'
Why? Because we had to evaluate the bool application before we could tell whether it was going to produce a Just result.
Chris Martin's answer covers func6 versus func7 very well. (In short, the difference is that, thanks to laziness, func6 #Maybe can decide whether the constructor used for the result should be Just or Nothing without actually having to look at any value within its argument.)
As for func9, what makes Monad necessary is that the function involves using values found in xs to decide on the functorial context of the result. (Synonyms for "functorial context" in this setting include "effects" and, as the solution you quote puts it, "structure of the computation".) For the sake of illustration, consider:
func9 (fmap read getLine) (putStrLn "Even!") (putStrLn "Odd!")
It is useful to compare the types of fmap, (<*>) and (>>=):
(<$>) :: Functor f => (a -> b) -> (f a -> f b) -- (<$>) = fmap
(<*>) :: Applicative f => f (a -> b) -> (f a -> f b)
(=<<) :: Monad f => (a -> f b) -> (f a -> f b) -- (=<<) = filp (>>=)
The a -> b function passed to fmap has no information about f, the involved Functor, and so fmap cannot change the effects at all. (<*>) can change the effects, but only by combining the effects of its two arguments -- the a -> b functions that might be found in the f (a -> b) argument have no bearing on that whatsoever. With (>>=), though, the a -> f b function is used precisely to generate effects from values found in the f a argument.
I suggest Difference between Monad and Applicative in Haskell as further reading on what you gain (and lose) when moving between Functor, Applicative and Monad.

Trouble explaining Haskell code with where and pattern match

I have hard time parsing how mf m y are assigned values or even why there can be 3 variables on the left side of assignment in where section.
Q: Can anyone explain what happens here in both cases? (that is for empty list and a list with some elements)
-- | A variant of 'foldl' that has no base case,
-- and thus may only be applied to non-empty structures.
--
-- #'foldl1' f = 'List.foldl1' f . 'toList'#
foldl1 :: (a -> a -> a) -> t a -> a
foldl1 f xs = fromMaybe (errorWithoutStackTrace "foldl1: empty structure")
(foldl mf Nothing xs)
where
mf m y = Just (case m of
Nothing -> y
Just x -> f x y)
(this is the source code for the foldl1 function).
Definitions in where clauses follow the same syntax as global definitions, so mf m y = ... defines a function named mf, which takes parameters named m and y.
I have hard time parsing how mf m y are assigned values or even why there can be 3 variables.
You do not define three variables here: you define a variable mf which is a function, and m and y are two arguments of the function mf.
We can make the function more elegant, and thus omit the m and y. mf can be defined as:
mf Nothing = Just . id
mf (Just x) = Just . f x
Mind that we can not simply make mf an outer function, since it uses a function f, with is a parameter of foldl1. So we put it in a where clause:
foldl1 :: (a -> a -> a) -> t a -> a
foldl1 f xs = fromMaybe (errorWithoutStackTrace "foldl1: empty structure")
(foldl mf Nothing xs)
where mf Nothing = Just . id
mf (Just x) = Just . f x
In the empty list case, foldl mf Nothing [] ~ Nothing by definition, so foldl1 will return the "empty structure" error.
When xs is not empty, then foldl1' is simply a left fold by foldl. In this case foldl has the type
foldl :: (Maybe a -> a -> Maybe a) -> Maybe a -> [a] -> Maybe a
which makes use of the combining function mf :: Maybe a -> a -> Maybe a defined in the where clause.

Applicative instance for sets (nested lists)

I am currently working on a personal project for my discreet maths class and am trying to formalize set theory in Haskell. A set as defined in our class is an arbitrary nesting of elements of a particular universe. I chose to represent this as the de facto standard nested list:
data Set a where
Empty :: Set a
Elem :: a -> Set a -> Set a
Set :: Set a -> Set a -> Set a
As a lazy Haskell programmer I want to write instances for all the standard typeclasses.
The Functor instance is trivial:
instance Functor Set where
fmap _ Empty = Empty
fmap f (Elem x set) = Elem (f x) set
fmap f (Set s set) = Set (fmap f s) $ fmap f set
Foldable and Traversable are also relatively easy to implement.
Not I'm stuck on Applicative. pure is also straightforward:
instance Applicative Set where
pure x = Elem x Empty
However, I'm stuck on defining ap for nested lists.
-- set has a monoid instance
(<*>) :: Set (a -> b) -> Set a -> Set b
Elem fx fxs <*> x = fmap fx x `mappend` (fxs <*> x)
Set fxs fxss <*> x = Set ???
For a normal, not nested list, the applicative instance takes the cartesian product of every function with every element and applies it:
fx <*> xs = [f x | f <- fx, x <- xs]
Somehow the nested list must preserve it's underlying structure. What is the correct instance?
Your instance is almost correct, just a few more suggestions:
instance Applicative Set where
pure x = Elem x Empty
-- the cartesian product of the empty set and x is empty
Empty <*> x = Empty
-- the cartesian product of x and the empty set is empty
x <*> Empty = Empty
-- if you encounter a function, apply it to the entire list
-- and append the result of the recursive call to the rest.
Elem fx fxs <*> x = fmap fx x `mappend` (fxs <*> x)
-- If you reach a level of nesting, go into the nested list
-- and prepend that to the rest.
Set fxs fxss <*> x = Set (fxs <*> x) (fxss <*> x)
This instance satisfies all the applicative laws:
pure id <*> x = x
pure f <*> pure x = pure $ f x
pure (.) <*> pure u <*> pure v <*> pure w = u <*> (v <*> w)
u <*> pure y = pure ($ y) <*> u

Is there a nicer way to apply a function to both elements of a pair in a list than a list comprehension?

I use this a fair bit:
a' = [ (f x, f y) | (x, y) <- a ]
Is there a better way to do that?
You can use the (***) operator from Control.Arrow
> map (f *** f) a
or define your own helper function
> let both f (x, y) = (f x, f y)
> map (both f) a
Alternative solution:
import Data.Bifunctor
bimap f f pair
Bifunctor.bimap is basically the same as Arrow.(***), but works for other bifunctors (like Either a b), too.
Digression:
The reason why there is nothing predefined for your case is that you can't write instances of Functor, Applicative etc for (,) having the same element type twice. With an own "vector-like" type you wouldn't have this problem:
data Pair a = Pair a a deriving Show
instance Functor Pair where
fmap f (Pair x y) = Pair (f x) (f y)
Now you can write things like map (fmap (+1)) [Pair 12 14, Pair 17 18]. Or if you want to use different operations on your Pair, you can go one step further:
instance Applicative Pair where
pure x = Pair x x
(Pair f g) <*> (Pair x y) = Pair (f x) (g y)
If you work a lot with same-element-type pairs, it could be useful to switch from (,) to such a type.
If you use lens, you can use over both f, or both %~ f. This has the advantage of being more composable -- for example, if you have a pair of lists, you can use something like both.mapped +~ toUpper (:: ([Char],[Char]) -> ([Char],[Char])).

Resources