Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
254 views
in Technique[技术] by (71.8m points)

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

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...