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.
As pointed out in Daniel's excellent answer, your problem is to compose
f
andg
whenf
as one argument andg
two. this could be writtenf ??? 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 becomesIf you are used to the
.:
operator, then this point free version is perfectly readable. I can also instead use(<$$$>) = fmap fmap fmap
and getYou could also use:
Idiomatic Haskell is whatever is easier to read, not necessarily what is most point-free.
Not "where possible", but "where it improves readability (or has other manifest advantages)".
To point-free your
A first step would be to move the
($)
right, and replace the one you have with a(.)
:Now, you can move it even further right:
and there you can immediately chop off one argument,
Then you can rewrite that as a prefix application of the composition operator,
and you can write
f (g x)
as
generally, here with
and
g = zip
, givingfrom which the argument
x
is easily removed. Then you can transform the prefix application of(.)
into a section and getBut, 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.
Another concise, point-free solution:
Equivalently: