Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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.

like image 958
JonathanZ supports MonicaC Avatar asked Nov 17 '12 00:11

JonathanZ supports MonicaC


People also ask

What does flip do in Haskell?

flip f takes its (first) two arguments in the reverse order of f. flip the order of the first two arguments of a function.

How do you pass arguments in Haskell?

You have to pass file1 etc. to runQuery like every other function argument: main = do (file1:file2:file3:_) <- getArgs checkdata command <- getLine runQuery file1 file2 file3 (words command) runQuery file1 file2 file3 ("queryname":parameter1:parameter2) = do ... Well that was simple.

What is point free Haskell?

Point free style means that the code doesn't explicitly mention it's arguments, even though they exist and are being used. This works in Haskell because of the way functions work.

How are higher-order functions used in Haskell?

In Haskell, a function that can take other functions as arguments or return functions is called a higher-order function. These are particularly useful in that they allow us to create new functions on top of the ones we already have, by passing functions as arguments to other functions.


2 Answers

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.

like image 101
Daniel Fischer Avatar answered Sep 16 '22 15:09

Daniel Fischer


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.

like image 39
Gabriella Gonzalez Avatar answered Sep 16 '22 15:09

Gabriella Gonzalez