1

I'm trying to use the . operator to write a function that takes three values and returns their maximum.

Obviously, the following work

max3 a b c = max a (max b c)
max3 a b c = max a $ max b c

but I would like to use .. I tried

max3 a b c = max a . max b c

but get the error

Couldn't match expected type `a0 -> Float' with actual type `Float'
In the first argument of `max', namely `b'

I know that the example is silly, but a nice explanation of the correct way to do this and why would be greatly appreciated.

2
  • One must remember that (.) isn't some built-in magic operator; it's a normal function defined as any other function would be. Commented Dec 23, 2016 at 9:25
  • @AJFarmar The issue (although I did not realize at the time of asking) was primarily that the error message was not helpful. I still don't understand why max should expect a0 -> Float. Commented Dec 23, 2016 at 13:11

2 Answers 2

6

Recall the definition of (.):

(f . g) x = f (g x)

You have the expression

max a (max b c)

which matches the right hand side of (f . g) x if we set f = max a, g = max b, and x = c. Using these substitutions on the left-hand side of the definition of (.), we get:

(max a . max b) c = max a (max b c)
Sign up to request clarification or add additional context in comments.

Comments

6

Let's introduce some more parentheses in your first example:

max3 a b c = (max a) ((max b) c)

Now compare that to the ones in your last one:

max3 a b c = (max a) . ((max b) c)

Or, if we write (.) in prefix notation:

max3 a b c = (.) (max a) ((max b) c)

And now we see why you get that error. In order to type-check, (max b) c needs to be a function:

(.)       :: (b     -> c    )  -> (a -> b   ) -> a -> c
max a     ::  Float -> Float
max b c   ::                           Float
                                  ^^^^^^^^^^^

We get a better error message if we use a constrained version of max instead:

maxFloat :: Float -> Float -> Float
maxFloat = max

max3 a b c = max a . max b c

Now the error message is a lot better:

Couldn't match expected type ‘a0 -> Float’ with actual type ‘Float’
Possible cause: ‘maxFloat’ is applied to too many arguments
In the second argument of ‘(.)’, namely ‘maxFloat b c’
In the expression: maxFloat a . maxFloat b c

That being said, let's actually tackle the problem:

max3 a b c = max a ((max b) c)
           = (max a . max b) c

Note that you can also write

max3 :: Ord a => a -> a -> a -> a   
max3 a b = max a . max b

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.