Haskell Applicative idiom? - haskell

I'm new to Haskell and am puzzling over how to best express some operations in the most idiomatic and clear way. Currently (there will be more to come) I'm puzzling over <*> (I'm not even sure what to call that).
For example, if I have, say
f = (^2)
g = (+10)
as representative functions (in practice they are more complex, but the key thing here is that they are different and distinct), then
concatMap ($ [1,2,3,4,10]) [(f <$>), (g <$>) . tail . reverse]
and
concat $ [(f <$>), (g <$>) . tail . reverse] <*> [[1,2,3,4,10]]
accomplish the same thing.
Is one of these more idiomatic Haskell, does one imply something an experienced reader of Haskell that the other does not. Perhaps there are additional (better) ways to express exactly the same thing. Are there conceptual differences between the two approaches that a novice Haskeller like myself may be missing?

Both your functions (f <$>) and (g <$>).tail.reverse return a monoid type (list in this case) so you can use mconcat to convert them into a single function. Then you can apply this function directly to the input list instead of wrapping it in another list and using concatMap:
mconcat [(f <$>), (g <$>).tail.reverse] $ [1,2,3,4,10]
To expand on this, a function a -> b is an instance of Monoid if b is a monoid. The implementation of mappend for such functions is:
mappend f g x = f x `mappend` g x
or equivalently
mappend f g = \x -> (f x) `mappend` (g x)
so given two functions f and g which return a monoid type b, fmappendg returns a function which applies its argument to f and g and combines the results using the Monoid instance of b.
mconcat has type Monoid a => [a] -> a and combines all the elements of the input list using mappend.
Lists are monoids where mappend == (++) so
mconcat [(f <$>), (g <$>).tail.reverse]
returns a function like
\x -> (fmap f x) ++ (((fmap g) . tail . reverse) x)

Personally for your example I would write
f = (^2)
g = (+10)
let xs = [1,2,3,4,10]
in (map f xs) ++ (map g . tail $ reverse xs)
In a very Applicative "mood", I would replace the part after in by
((++) <$> map f <*> map g . tail . reverse) xs
which I actually don't think is more readable in this case. If you don't directly understand what it means, spend some time on understanding the Applicative instance of ((->) a) (Reader).
I think the choice really depends on what you're trying to do, i.e. what your output is supposed to mean. In your example the task is very abstract (basically just showcasing what Applicative can do), so it's not directly obvious which version to use.
The Applicative instance of [] intuitively relates to combinations, so I would use it in a situation like this:
-- I want all pair combinations of 1 to 5
(,) <$> [1..5] <*> [1..5]
If you would have many functions, and you would want to try all combinations of these functions with a number of arguments, I would indeed use the [] instance of Applicative. But if what you're after is a concatenation of different transformations I would write it as such (which I did, above).
Just my 2 cents as a medium-experience Haskeller.

I sometimes struggle with the similar problem. You have single element but multiple functions.
Usually we have multiple elements, and single function: so we do:
map f xs
But it's not the problem in Haskell. The dual is as easy:
map ($ x) fs
The fact, that your x is actually a list, and you want to concat after the map, so you do
concatMap ($ xs) fs
I cannot really understand what happens in the second equation directly, even I can reason it does the same as first one using applicative laws.

Related

Use cases for functor/applicative/monad instances for functions

Haskell has Functor, Applicative and Monad instances defined for functions (specifically the partially applied type (->) a) in the standard library, built around function composition.
Understanding these instances is a nice mind-bender exercise, but my question here is about the practical uses of these instances. I'd be happy to hear about realistic scenarios where folks used these for some practical code.
A common pattern that involves Functor and Applicative instances of functions is for example (+) <$> (*2) <*> (subtract 1). This is particularly useful when you have to feed a series of function with a single value. In this case the above is equivalent to \x -> (x * 2) + (x - 1). While this is very close to LiftA2 you may extend this pattern indefinitely. If you have an f function to take 5 parameters like a -> a -> a -> a -> a -> b you may do like f <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2) and feed it with a single value. Just like in below case ;
Prelude> (,,,,) <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2) $ 10
(12.0,20.0,11.0,7.0,5.0)
Edit: Credit for a re-comment of #Will Ness for a comment of mine under another topic, here comes a beautiful usage of applicative over functions;
Prelude> let isAscending = and . (zipWith (<=) <*> drop 1)
Prelude> isAscending [1,2,3,4]
True
Prelude> isAscending [1,2,5,4]
False
Sometimes you want to treat functions of the form a -> m b (where m is an Applicative) as Applicatives themselves. This often happens when writing validators, or parsers.
One way to do this is to use Data.Functor.Compose, which piggybacks on the Applicative instances of (->) a and m to give an Applicative instance for the composition:
import Control.Applicative
import Data.Functor.Compose
type Star m a b = Compose ((->) a) m b
readPrompt :: Star IO String Int
readPrompt = Compose $ \prompt -> do
putStrLn $ prompt ++ ":"
readLn
main :: IO ()
main = do
r <- getCompose (liftA2 (,) readPrompt readPrompt) "write number"
print r
There are other ways, like creating your own newtype, or using ready-made newtypes from base or other libraries.
here an application of the bind function that I used for solving the Diamond Kata. Take a simple function that mirrors its input discarding the last element
mirror :: [a] -> [a]
mirror xs = xs ++ (reverse . init) xs
let's rewrite it a bit
mirror xs = (++) xs ((reverse . init) xs)
mirror xs = flip (++) ((reverse . init) xs) xs
mirror xs = (reverse . init >>= flip (++)) xs
mirror = reverse . init >>= flip (++)
Here is my complete implementation of this Kata: https://github.com/enolive/exercism/blob/master/haskell/diamond/src/Diamond.hs

Removing duplication (with Applicative ((->) t), perhaps?)

I was playing around with a simple function for someone else's Stack Overflow question, and wrote the expression:
f a x ++ f a y
Obviously this is the best way to write that expression in real life, given I have all those variables in scope anyway, but I saw the duplication of f a, and thought "Hey, maybe you can remove that with the Applicative instance for functions". I wound up with:
liftA2 (++) (flip f x) (flip f y) a
which is just awful. Is there some nicer way to remove this duplication?Obviously I could also remove the duplication by binding f a to something in a where clause, but this was intended as an exercise in using built-in functions.
You could do
((++) `on` f a) x y
That doesn't use Applicative, though (sorry).
[...] maybe you can remove that with the Applicative instance for functions.
Do you have to use the Applicative instance of ((->) t)? If you just want to get rid of the duplicated f a, why not use the list monad, instead?
[x, y] >>= f a
or, equivalently,
f a =<< [x, y]
Example:
λ> let f :: Int -> Int -> [Int]; f a x = [a .. x]
λ> f 1 2 ++ f 1 3
[1,2,1,2,3]
λ> [2, 3] >>= f 1
[1,2,1,2,3]
λ> f 1 =<< [2, 3]
[1,2,1,2,3]
Bikeshedding is fun! Another option would be to use the Monoid instance for functions:
(($x) <> ($y)) (f a)
Since the question hinted at a solution using Applicative (although other answers are more elegant)...
((++) <$> ($ x) <*> ($ y)) (f a)

Difference between concatMap f xs and concat $ map f xs?

Presumably they do exactly the same thing, concatMap f xs and concat $ map f xs. Why would I choose one over another?
I imagine it may be an optimization. If so, is this still the case with GHC 7.8?
It is the case that concatMap f xs = concat (map f xs) as you suspect. Thus, for correctness purposes you should consider them interchangeable. We can examine their definitions to learn a little more, though.
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f = foldr ((++) . f) []
concat :: [[a]] -> [a]
concat = foldr (++) []
In particular, this means that concat . map f expands to foldr (++) [] . map f. Now using a thing known as the "universal property of fold" we can see that foldr g z . map f = foldr (g . f) z for any (g, z, f) such as the choice ((++), f, []) we use above. This demonstrates that concatMap f = concat . map f like we want.[0]
So why are they defined differently? Because foldr ((++) . f) [] is always going to be faster than foldr (++) [] . map f since, in a really pathological case, the latter suggests two separate recursions. Due to laziness, it's unlikely that two recursions would ever be performed, though, so what gives?
The real reason is that there are more complex fusion laws available to the compiler such as those which combine two sequential foldrs or which define interactions between foldr and unfoldr. These are kind of finicky to use as they depend upon being able to look at the surface syntax of a fragment of code and detect possible simplifications. A lot of work goes into getting consistently firing fusion laws.
But one thing we can do is encourage people to use higher order combinators with optimization laws pre-applied. Since foldr (++) [] . map f is never going to be faster than foldr ((++) . f) [] we can take a shortcut and pre-apply the universal law simplification. This will improve the likelihood of fusion laws firing elsewhere to best optimize a list production pipeline.
[0] Why does this law work? Roughly, the universal law of foldr states that if you have any function q such that q [] = z and q (a:as) = f a (q as) then that q must be and is foldr f z. Since q = foldr g z . map f can be shown to have q [] = z and q (a:as) = g (f a) (q as) then it must be a fold like foldr (g . f) z like we want.

Clarify role of list monad operator

I came across a Haskell function that tells whether a list is sorted, and I'm having trouble understanding how it works.
The code in question is
f = zipWith (<=) <*> tail
which I understand to be equivalent (in point-ful style) to
f' xs = zipWith (<=) xs (tail xs)
and as an example returns
f [4, 5, 1] == [True,False]
I take it that it has something to do with the list monad and sequential application, but would appreciate if someone could make the meaning more clear to me. What exactly is <*> doing here?
The <*> here isn't acting on the [a] applicative, it's acting in the (->) a applicative instance.
Essentially
instance Applicative ((->) a) where
pure = const -- same as monadic return
f <*> a = \x -> f x (a x)
So it acts like function application, but also wraps the application in a function and gives the argument to both sides.
So expanding your function
zipWith (<=) <*> tail
\x -> zipWith (<=) x (tail x)
\(x:xs) -> zipWith (<=) (x:xs) xs
In general it's correct to view <*> as just function application + some extra goodies. You can almost read it as whitespace!
<*> is actually from (->) a as Applicative Functor. It is a S-combinator which distributes the argument (list xs in your expansion) to two functions (zipWith (<=) and tail) in the manner that you specified in the expansion: (f <*> g) x = f x (g x).
To understand this, you need to check the type (<*>) is applied to. Since both of its arguments are a->b, we are talking about a->b as Applicative Functor - not List.

Haskell: How is join a natural transformation?

I can define a natural transformation in Haskell as:
h :: [a] -> Maybe a
h [] = Nothing
h (x:_) = Just x
and with a function k:
k :: Char -> Int
k = ord
the naturality condition is met due to the fact that:
h . fmap k == fmap k . h
Can the naturality condition of the List monad's join function be demonstrated in a similar way? I'm having some trouble understanding how join, say concat in particular, is a natural transformation.
Okay, let's look at concat.
First, here's the implementation:
concat :: [[a]] -> [a]
concat = foldr (++) []
This parallels the structure of your h where Maybe is replaced by [] and, more significantly, [] is replaced by--to abuse syntax for a moment--[[]].
[[]] is a functor as well, of course, but it's not a Functor instance in the way that the naturality condition uses it. Translating your example directly won't work:
concat . fmap k =/= fmap k . concat
...because both fmaps are working on only the outermost [].
And although [[]] is hypothetically a valid instance of Functor you can't make it one directly, for practical reasons that are probably obvious.
However, you can reconstruct the correct lifting as so:
concat . (fmap . fmap) k == fmap k . concat
...where fmap . fmap is equivalent to the implementation of fmap for a hypothetical Functor instance for [[]].
As a related addendum, return is awkward for the opposite reason: a -> f a is a natural transformation from an elided identity functor. Using : [] the identity would be written as so:
(:[]) . ($) k == fmap k . (:[])
...where the completely superfluous ($) is standing in for what would be fmap over the elided identity functor.

Resources