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.
flip f takes its (first) two arguments in the reverse order of f. flip the order of the first two arguments of a function.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With