How do I re-write a Haskell function of two argument to point-free style - haskell

I have the following function in Haskell
agreeLen :: (Eq a) => [a] -> [a] -> Int
agreeLen x y = length $ takeWhile (\(a,b) -> a == b) (zip x y)
I'm trying to learn how to write 'idiomatic' Haskell, which seem to prefer using . and $ instead of parenthesis, and also to prefer pointfree code where possible. I just can't seem to get rid of mentioning x and y explicitly. Any ideas?
I think I'd have the same issue with pointfreeing any function of two arguments.
BTW, this is just in pursuit of writing good code; not some "use whatever it takes to make it pointfree" homework exercise.
Thanks.
(Added comment)
Thanks for the answers. You've convinced me this function doesn't benefit from pointfree. And you've also given me some great examples for practicing transforming expressions. It's still difficult for me, and they seem to be as essential to Haskell as pointers are to C.

and also to prefer pointfree code where possible.
Not "where possible", but "where it improves readability (or has other manifest advantages)".
To point-free your
agreeLen x y = length $ takeWhile (\(a,b) -> a == b) (zip x y)
A first step would be to move the ($) right, and replace the one you have with a (.):
agreeLen x y = length . takeWhile (\(a,b) -> a == b) $ zip x y
Now, you can move it even further right:
agreeLen x y = length . takeWhile (uncurry (==)) . zip x $ y
and there you can immediately chop off one argument,
agreeLen x = length . takeWhile (uncurry (==)) . zip x
Then you can rewrite that as a prefix application of the composition operator,
agreeLen x = (.) (length . takeWhile (uncurry (==))) (zip x)
and you can write
f (g x)
as
f . g $ x
generally, here with
f = (.) (length . takeWhile (uncurry (==)))
and g = zip, giving
agreeLen x = ((.) (length . takeWhile (uncurry (==)))) . zip $ x
from which the argument x is easily removed. Then you can transform the prefix application of (.) into a section and get
agreeLen = ((length . takeWhile (uncurry (==))) .) . zip
But, that is less readable than the original, so I don't recommend doing that except for practicing the transformation of expressions into point-free style.

You could also use:
agreeLen :: (Eq a) => [a] -> [a] -> Int
agreeLen x y = length $ takeWhile id $ zipWith (==) x y
Idiomatic Haskell is whatever is easier to read, not necessarily what is most point-free.

As pointed out in Daniel's excellent answer, your problem is to compose f and g when f as one argument and g two. this could be written f ??? g with the correct operator (and with a type signature of (c -> d) -> (a -> b -> c) -> a -> b -> d.
This correspond to the (.).(.) operator (see there) which is sometimes defines as .:. In that case your expression becomes
length . takeWhile (uncurry (==)) .: zip
If you are used to the .: operator, then this point free version is perfectly readable. I can also instead use (<$$$>) = fmap fmap fmap and get
length . takeWhile (uncurry (==)) <$$$> zip

Another concise, point-free solution:
agreeLen = ((length . takeWhile id) .) . zipWith (==)
Equivalently:
agreeLen = (.) (length . takeWhile id) . zipWith (==)

Related

Haskell dot operator with sort and (++) [duplicate]

This question already has answers here:
Haskell function composition operator of type (c→d) → (a→b→c) → (a→b→d)
(6 answers)
Closed last year.
I am learning haskell at the moment and trying to figure out all the rules of prefix, infix, precedence, etc.
While trying to implement a function which appends two lists and sorts them I started with:
appendAndSort :: [a] -> [a] -> [a]
appendAndSort = sort . (++)
which does no compile.
Following:
appendAndSort :: Ord a => [a] -> [a] -> [a]
appendAndSort = (sort .) . (++)
on the other hand does work.
Why do I have to add a second dot at sort and parentheses around it?
Let's start with a version that uses explicit parameters.
appendAndSort x y = sort (x ++ y)
Writing ++ as a prefix function rather than an operator yields
appendAndSort x y = sort ((++) x y)
Knowing that (f . g) x == f (g x), we can identify f == sort and g == (++) x to get
appendAndSort x y = (sort . (++) x) y
which lets us drop y as an explicit parameter via eta conversion:
appendAndSort x = sort . (++) x
The next step is to repeat the process above, this time with (.) as the top most operator to write as a prefix function,
appendAndSort x = (.) sort ((++) x)
then apply the definition of . again with f == (.) sort and g == (++):
appendAndSort x = (((.) sort) . (++)) x
and eliminate x via eta conversion
appendAndSort = ((.) sort) . (++)
The last step is to write (.) sort as an operator section, and we're done with our derivation.
appendAndSort = (sort .) . (++)
The expression (f . g) x means f (g x).
Coherently, (f . g) x y means f (g x) y.
Note how y is passed as a second parameter to f, not to g. The result is not f (g x y).
In your case, (sort . (++)) x y would mean sort ((++) x) y, which would call sort with first argument (++) x (the function which prepends the list x to its list argument), and with second argument y. Alas, this is ill-typed since sort only takes one argument.
Consequently, this is also invalid
appendAndSort x y = (sort . (++)) x y
hence so is this
appendAndSort = sort . (++)
By contrast, ((f .) . g) x y does work as expected. Let's compute:
((f .) . g) x y
= -- same reasoning as above, y is passed to (f.), not g
(f .) (g x) y
= -- application associates on the left
((f .) (g x)) y
= -- definition of `(f.)`
(f . (g x)) y
= -- definition of .
f ((g x) y)
= -- application associates on the left
f (g x y)
So this really makes y to be passed to g (and not f).
In my opinion the "idiom" (f .) . g isn't worth using. The pointful \x y -> f (g x y) is much simpler to read, and not terribly longer.
If you really want, you can define a custom composition operator to handle the two-argument case.
(.:) f g = \x y -> f (g x y)
Then, you can write
appendAndSort = sort .: (++)

Haskell point-free style with no functions in the expression

I've been trying to take some simple functions and convert them to point-free style for practice.
I started with something like this:
zipSorted x y = (zip . sort) y $ sort x --zipSorted(x, y) = zip(sort(y), sort(x))
and eventually converted it to
zipSorted = flip (zip . sort) . sort
(I'm not sure if this is even the best way to do it but it works)
Now I'm trying to further reduce this expression by not having it depend on zip and sort at all. In other words, I'm looking for this function: (I think its a combinator if my vocabulary isn't mistaken)
P(f, g, x, y) = f(g(y), g(x))
The fact that sort is present twice but only passed in once hinted to me that I should use the applicative functor operator <*> but I can't figure out how for some reason.
From my understanding, (f <*> g)(x) = f(x, g(x)), so I've tried re-writing the first point-free expression in this form:
flip (zip . sort) . sort
(.) (flip $ zip . sort) sort
(flip (.)) sort $ flip (zip . sort)
(flip (.)) sort $ flip $ (zip .) sort
It seems that sort should be x, (flip (.)) should be f, and flip . (zip .) should be g.
p = (flip (.)) <*> (flip . (zip .))
p sort [2, 1, 3] [4, 1, 5]
yields [(1, 1), (4, 2), (5, 3)] as expected, but now I'm lost on how to pull the zip out. I've tried
p = (flip (.)) <*> (flip . (.))
p zip sort [2, 1, 3] [4, 1, 5]
but this doesn't work. Is there a way to convert that expression to a combinator that factors out zip?
Let's start from the beginning:
zipSort x y = zip (sort y) (sort x)
It's slightly weird that it uses its arguments in the opposite order, but we can fix that later with flip.
Here we have a general pattern of a "combining" function of two arguments (here: zip) being passed two values transformed by another function. If we had the same base argument but different transformers, this would have been a liftA2 pattern:
c (f x) (g x)
==
liftA2 c f g x
But here it's the opposite: We have the same transform function on both sides (here: sort), but different arguments (x and y). That's on:
c (f x) (f y)
==
(c `on` f) x y
In your case we get:
zip (sort y) (sort x)
(zip `on` sort) y x
flip (zip `on` sort) x y
So
zipSort = flip (zip `on` sort) -- or: flip (on zip sort)
We can further pull out zip and sort by recognizing the standard two-argument-into-one-argument-function composition:
(\x y -> f (g x y)) == (f .) . g
giving
zipSort = ((flip .) . on) zip sort
Note that this function is less general than the pointful version, however. The original function has type
(Ord a, Ord b) => [a] -> [b] -> [(b, a)]
but the pointfree version has type
(Ord a) => [a] -> [a] -> [(a, a)]
because unifying the two sorts forces them to have the same type.
I just asked lambdabot for the answer, rather than trying to work it out by hand:
<amalloy> #pl \zip sort x y -> (zip . sort) y $ sort x
<lambdabot> join . (((.) . flip) .) . (.)

Filter a list of tuples by fst

What I'm trying to do is not really solve a problem, but more to learn how to write Haskell code that composes/utilizes basic functions to do it.
I have a function that takes a list of tuples (String, Int) and a String, and returns a tuple whose fst matches the given String.
This was fairly easy to do with filter and lambda, but what I want to do now, is remove the rightmost argument, ie. I want to refactor the function to be a composition of partially applied functions that'll do the same functionality.
Original code was:
getstat :: Player -> String -> Stat
getstat p n = head $ filter (\(n', v) -> n' == n) $ stats p
New code is:
getstat :: Player -> String -> Stat
getstat p = head . (flip filter $ stats p) . cmpfst
where cmpfst = (==) . fst . (flip (,)) 0 -- Wrong :-\
The idea is to flip the filter and partially apply by giving in the list of tuples (stats p) and then compose cmpfst.
cmpfst should be String -> (String, Int) -> Bool so that when String argument is applied, it becomes a -> Bool which is good for the filter to pass in tuples, but as you can see - I have problems composing (==) so that only fst's of given tuples are compared.
P.S. I know that the first code is likely cleaner; the point of this task was not to write clean code but to learn how to solve the problem through composition.
Edit:
I understand well that asking for a head on an possibly empty list is a bad programming that'll result in a crash. Like one earlier poster mentioned, it is very simply and elegantly resolved with Maybe monad - a task I've done before and am familiar with.
What I'd like the focus to be on, is how to make cmpfst composed primarily of basic functions.
So far, the furthest I got is this:
getstat :: Player -> String -> Stat
getstat p = head . (flip filter $ stats p) . (\n' -> (==(fst n')) . fst) . (flip (,)) 0
I can't get rid of the (a -> Bool) lambda by composing and partially applying around (==). This signals, to me, that I either don't understand what I'm doing, or it's impossible using (==) operator in the way I imagined.
Furthermore, unless there's no exact solution, I'll accept signature-change solution as correct one. I'd like not to change the signature of the function simply because its a mental exercise for me, not a production code.
If I were writing this function, I'd probably have given it this type signature:
getstat :: String -> Player -> Stat
This makes it easy to eta-reduce the definition to
getstat n = head . filter ((== n) . fst) . stats
In a comment, you reached
getstat p = head . (flip filter $ stats p) . (\n (n', v) -> n' == n)
I wonder if there's a nicer composition that can eliminate the anon f.
Well, here it is
\n (n', v) -> n' == n
-- for convenience, we flip the ==
\n (n', v) -> n == n'
-- prefix notation
\n (n', v) -> (==) n n'
-- let's remove pattern matching over (n', v)
\n (n', v) -> (==) n $ fst (n', v)
\n x -> (==) n $ fst x
-- composition, eta
\n -> (==) n . fst
-- prefix
\n -> (.) ((==) n) fst
-- composition
\n -> ((.) . (==) $ n) fst
-- let's force the application to be of the form (f n (g n))
\n -> ((.) . (==) $ n) (const fst $ n)
-- exploit f <*> g = \n -> f n (g n) -- AKA the S combinator
((.) . (==)) <*> (const fst)
-- remove unneeded parentheses
(.) . (==) <*> const fst
Removing p is left as an exercise.

Point-free equivalent

I have this function from another SO question,
f :: Ord a => [a] -> [(a, Int)]
f xs = zipWith (\x ys -> (x, length $ filter (< x) ys)) xs (inits xs)
I'm trying to write it in point-free style,
f = flip (zipWith (\x -> (,) x . length . filter (< x))) =<< inits
Is it possible to get rid of that x ?
It's possible, but absolutely not worth the pain. To directly answer your question, LambdaBot on FreeNode reports:
f = flip (zipWith (liftM2 (.) (,) ((length .) . filter . flip (<)))) =<< inits
At this point the function has lost whatever clarity it had, and has become unmaintainable. Here you'd do much better to introduce real names. Remember, just because we can make things point free does not mean we should.
As a general rule: if a variable turns up more than once in an expression, it's probably not a good idea to make it point-free. If you're determined however, the least unreadable way is with the Arrow combinators, because that makes it pretty clear where the data flow is "split". For the xs I'd write
uncurry (zipWith (...)) . (id &&& inits)
For x, the same method yields
zipWith ( curry $ uncurry(,) . (fst &&& length . uncurry filter . first(>)) )
This is even longer than the (->)-monad solution that you've used and lambdabot suggests, but it looks far more organised.
The point of pointfree style is not just omitting names for values, but preferring names for functions. This is significantly easier to do when you use very small definitions. Of course any code is going to become unreadable if you inline everything and don’t use good names.
So let’s start with your original function, and split it into a few smaller definitions.
f xs = zipWith combine xs (inits xs)
combine x xs = (x, countWhere (< x) xs)
countWhere f xs = length (filter f xs)
Now we can easily make these definitions pointfree in a readable way.
f = zipWith combine <*> inits
where combine = compose (,) countLessThan
compose = liftA2 (.)
countLessThan = countWhere . flip (<)
countWhere = length .: filter
(.:) = (.) . (.)
Using names judiciously and preferring composition over application allows us to factor code into small, easily understood definitions. Named parameters are the equivalent of goto for data—powerful, but best used to build reusable higher-level structures that are easier to understand and use correctly. These compositional combinators such as (.) and <*> are to data flow what map, filter, and fold are to control flow.
My stab at it:
f :: Ord a => [a] -> [(a, Int)]
f = zip <*> ((zipWith $ (length .) . filter . (>)) <*> inits)
Here I replaced (<) with (>) to have (length .) . filter . (>) as a function with arguments in the right order: a->[a]->Int. Passing it to zipWith, we get [a]->[[a]]->[Int].
Assuming we have [a] on input, we can see this as f ([[a]]->[Int]) for Applicative ((->) [a]), which can be combined with inits :: f [[a]] with <*> :: f ([[a]]->[Int])->f [[a]]->f [Int]. This gives us [a]->[Int], now need to consume both [a] and [Int] in parallel. zip is already of the right type: [a]->[Int]->[(a,Int)] to apply with <*>.
Not saying I recommend this, but the King of Pointfree is Control.Arrow
import Control.Arrow
-- A special version of zipWith' more amenable to pointfree style
zipWith' :: ((a, b) -> c) -> ([a], [b]) -> [c]
zipWith' = uncurry . zipWith . curry
f :: Ord a => [a] -> [(a, Int)]
f = zipWith' (fst &&& (length <<< uncurry filter <<< first (>))) <<< id &&& inits
Let me reclarify here—I really don't recommend this unless your intention is to somehow generalize the kind of arrow your program is operating in (e.g. into Arrowized FRP perhaps).
With the well-known
(f .: g) x y = f (g x y)
it is a semi-readable
zipWith (curry (fst &&& uncurry (length .: (filter . flip (<))) )) <*> inits
-- \(x,ys) -> (x , length ( (filter . flip (<)) x ys) )
Using Control.Applicative (f <*> g $ x = f x (g x), the S combinator), and Control.Arrow (as others, but a little bit differently).

How to map a list of functions over multiple arguments in Haskell?

I have three functions (getRow,getColumn,getBlock) with two arguments (x and y) that each produce a list of the same type. I want to write a fourth function that concatenates their outputs:
outputList :: Int -> Int -> [Maybe Int]
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]
The function works, but is there a way to rewrite the double map (with three '$'s) to a single map?
import Data.Monoid
outputList :: Int -> Int -> [Maybe Int]
outputList = mconcat [getRow, getColumn, getBlock]
You deserve an explanation.
First, I'll explicitly note that all these functions have the same type.
outputList, getRow, getColumn, getBlock :: Int -> Int -> [Maybe Int]
Now let's start with your original definition.
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]
These functions result in a [Maybe Int], and a list of anything is a monoid. Monoidally combining lists is the same as concatenating the lists, so we can replace concat with mconcat.
outputList x y = mconcat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]
Another thing that's a monoid is a function, if its result is a monoid. That is, if b is a monoid, then a -> b is a monoid as well. Monoidally combining functions is the same as calling the functions with the same parameter, then monoidally combining the results.
So we can simplify to
outputList x = mconcat $ map ($ x) [getRow,getColumn,getBlock]
And then again to
outputList = mconcat [getRow,getColumn,getBlock]
We're done!
The Typeclassopedia has a section about monoids, although in this case I'm not sure it adds that much beyond the documentation for Data.Monoid.
As a first step we observe that your definition
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]
can be rewritten using the function composition operator (.) instead of the function application operator ($) as follows.
outputList x y = (concat . map ($ y) . map ($ x)) [getRow,getColumn,getBlock]
Next we notice that map is another name for fmap on lists and satisfies the fmap laws, therefore, in particular, we have map (f . g) == map f . map g. We apply this law to define a version using a single application of map.
outputList x y = (concat . map (($ y) . ($ x))) [getRow,getColumn,getBlock]
As a final step we can replace the composition of concat and map by concatMap.
outputList x y = concatMap (($ y) . ($ x)) [getRow,getColumn,getBlock]
Finally, in my opinion, although Haskell programmers tend to use many fancy operators, it is not a shame to define the function by
outputList x y = concatMap (\f -> f x y) [getRow,getColumn,getBlock]
as it clearly expresses, what the function does. However, using type class abstractions (as demonstrated in the other answer) can be a good thing as you might observe that your problem has a certain abstract structure and gain new insights.
I would go with #dave4420's answer, as it's most concise and expresses exactly what you mean. However, if you didn't want to rely on Data.Monoid then you could rewrite as follows
Original code:
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]
Fuse the two maps:
outputList x y = concat . map (($y) . ($x)) [getRow,getColumn,getBlock]
Replace concat . map with concatMap:
outputList x y = concatMap (($y) . ($x)) [getRow,getColumn,getBlock]
And you're done.
Edit: aaaaand this is exactly the same as #Jan Christiansen's answer. Oh well!

Resources