Pointfree Exercises in Haskell Trail

Hi, guys!

I’ve been loving the Haskell trail so far, having a great time working my way through the exercises. I’ve made my way through half of Learn you a Haskell in the last year, so these exercises have been a great way of learning my knowledge (or lack thereof to the test). As a general point of feedback, I have so far found the exercises to be right at the limit of my mental capabilities - I feel I am literally stretching my mind as I’m working through them, just scraping across the line to finish the exercise, but learning a lot on the process.

I’ve made it as far as the Pointfree Style exercise and am now throwing my hands in the air. Here’s the one that got me:

isDigit :: Char -> Bool
isDigit x = elem x "1234567890"

How on God’s green earth am I able to rewrite this in pointfree style?

I understand that, in effect, I am trying to:

Produce a function, that when applied, calls elem with its first parameter and 1234567890 as its second parameter.

I have no idea how I would even begin doing that. As I understand currying, functions are built left to right. eg:

something :: a -> b -> c

Is a function that takes a as its first argument, and returns a function that then takes b as its second argument, producing c.

In effect I am trying to return a function that takes an a and applies it to b. Is this even possible?

something :: a -> b -> c

Is a function that takes a as its first argument, and returns a function that then takes b as its second argument, producing c.

Close!

It’s a function that takes a as its only argument and returns a function that takes b as its only argument. All fns in Haskell take only a single argument.

There are at least two ways to write this in point-free style. I’d prefer to use this: http://haddocks.fpcomplete.com/fp/7.8/20140916-162/base/Prelude.html#v:flip

See if you can figure that out. If not, ping me and I’ll help.

Thanks for the reply, Ben!

Yes, that’s exactly what I meant, except for the part where you used the right words in the right order to convey the correct meaning. :stuck_out_tongue_closed_eyes:

Yes! Flip!! How could I have been so foolish?

Forgive me, I have failed you. My dreams of a career as a Haskell-er at thoughtbot are shattered.

Thanks again, Ben. :blush:

1 Like

Next question:

The following functions are in pointfree style:

Example One

--- Lispy
hasUppercaseWord = any(all(isUpper))

--- Pointfree
hasUppercaseWord = any . all $ isUpper

Example Two

--- Lispy
reversewords = unwords(reverse(words))
--- Pointfree
reverseWords = unwords . reverse . words

In example one, to get the correct order of precedence, we use a combination of $ and .. In the second, we use two .s. What gives?

While you can get rid of ($)s by adding parenthesis, you can’t do the same with (.). If you wanted to translate the point-free versions to “Lispy”, you’d have to do it like this:

hasUppercaseWord xs = any (all isUpper xs)

reverseWords xs = unwords (reverse (words xs))

Here, you can see they aren’t actually that similar, which is why the point-free versions work out differently.

In the first example, the ($) is actually redundant. Function application binds tightest in Haskell, so just putting all and isUpper next to each other is enough to form a function that accepts a list and returns True if all elements are upper-case. This can then be composed with any using (.).

hasUppercaseWord = any . all isUpper

This is similar to something like:

secondElement = head . drop 1

In the second example, words is not an argument to reverse – that wouldn’t make sense. So there’s no application (implied or made explicit by ($)), you just compose each function with (.).

1 Like

Brilliant answer, @pat. Thank you - this helps a lot.

As a point of general feedback, I feel I struggle with the pointfree exercises because I can’t clearly see with my eyes where each function ends and begins (eg. what’s an argument and what’s the next function) because the function names are all quite unfamiliar to me. I guess this is just a familiarity thing that will go away with time!

I’ve bought Maybe Haskell last night, and this is helping a lot more too. In all honesty, I feel as if I skimmed over too much of Learn you a Haskell as it was perhaps more dense than I gave it credit for. I’m paying for that now. :smile:

Nice. I really enjoyed it. I suspect you will too.