el_hipopotamo_agil (1) [Avatar] Offline
I am really struggling with Chapter 9, I cannot wrap my head around the "Cup" example program. For reference, all of the code presented in the book is as follows.

cup oz = \message -> message oz

coffeeCup = cup 12
getOz aCup = aCup (\oz -> oz)

drink aCup ozDrank = if ozDiff >= 0
                     then cup (oz - ozDrank)
                     else cup 0
 where oz = getOz aCup
       ozDiff = oz - ozDrank

isEmpty aCup = (getOz aCup) == 0

afterManySips = foldl drink coffeeCup [1,1,1,1,1]

So, to start with, we have:

cup oz = \message -> message oz

As I understand this, we have a function named "cup" that takes a single parameter named "oz" for the definition. This function returns a lambda that takes a single parameter message, which calls the function that matches "message" param, passing it the "oz" value as the function's param.

So is this an example of partial application? I'll be honest and I find Ch. 4 the hardest to grok in Unit 1 (besides Ch. 9). We are returning a functional object to the caller at the end of the day?


coffeeCup = cup 12

So now, coffeeCup is assigned a lambda that can pass "messages" with a parameter "12". But how do I do that? How does one specify the "message" part of the lambda?


getOz aCup = aCup (\oz -> oz)

Ok now my head explodes. I don't understand this at all. I have a function "getOz" that takes a parameter, supposedly a "coffeeCup" object, right? Or is that assumption wrong? On the parameter object itself (aCup), why are we passing it a lambda function? What is aCup supposed to be actually? Is it a "coffeeCup" object? If so, I thought the function "coffeeCup" takes no params...

I just find all of this immensely confusing. I'm going to jump ahead to Chapter 10 for now, but I would really like to understand what is going on here.

Thank you!
Mark Elston (113) [Avatar] Offline
I had a question about this same topic when I read it last year. You might want to take a look at this discussion.
Mark Elston (113) [Avatar] Offline
But to answer the specific question at the bottom of your post, getOz is a function that takes a second function (call it a function object, if that helps). This parameter, in turn, takes a function whose parameter is a number of ounces. And, in fact, this is exactly what cup is defined to be!

So, getOz takes a cup (for example) object, and passes it a function that is intended to extract the number of ounces in that cup. How does it do that? Well, the cup object is really a function that takes the passed in function and calls it with the number of ounces it contains. Since the function used in getOz simply returns its parameter unchanged the net result is that getOz 'extracts' the ounces from its aCup parameter.

It really takes a while for this to sink in. I think I struggled with this example almost as much as I struggled to come to grips with monads. smilie