1

Given the following function

multThree :: (Num a) => a -> a -> a -> a  
multThree x y z = x * y * z  

and this description of it:

What really happens when we do multThree 3 5 9 or ((multThree 3) 5) 9? First, 3 is applied to multThree, because they're separated by a space. That creates a function that takes one parameter and returns a function. So then 5 is applied to that, which creates a function that will take a parameter and multiply it by 15. 9 is applied to that function and the result is 135 or something. Remember that this function's type could also be written as multThree :: (Num a) => a -> (a -> (a -> a)).

I interpret this as follows and want to be sure that this is correct:

((multThree 3) 5) 9 =
((3*y*z)5)9 =
(15*z)9 =
15*9
= 135

Is this the correct interpretation of multThree's functionality as described in this paragraph?

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
cody53982
  • 21
  • 2
  • 1
    It is known as Currying. https://wiki.haskell.org/Currying – Saurabh kukade Sep 09 '21 at 06:38
  • I think talking about currying here is more confusing than helpful. Especially since currying is converting a function taking a tuple to a new function taking a single argument, but there is no tuple here. – Micha Wiedenmann Sep 09 '21 at 06:59
  • 1
    All functions are already curried in Haskell. You don't really see the difference until you *uncurry* a function. `uncurry multThree :: (a, a) -> a -> a`. – chepner Sep 09 '21 at 11:36
  • 1
    (The combination of currying and the right-associativity of `->` is what lets you informally treat `multThree` as a function of three arguments, rather than a higher-order function that returns a function.) – chepner Sep 09 '21 at 11:39

2 Answers2

6

You are close but you miss a crucial point. ((3*y*z)5)9 is not a valid expression. In particular, while multThree in multThree 9 is a function, 3*y*z (the thing you substituted multThree with) is no longer a function. (Note also that y and z are used without being defined). To fix the problem we will rewrite multThree as

multThree = (\x -> (\y -> (\z -> x * y * z)))
-- or dropping all the unnecessary brackets
multThree = \x -> \y -> \z -> x * y * z

Now you can substitute and all works out:

multThree 3 5 9
= (\x -> \y -> \z -> x * y * z) 3 5 9
= (\y -> \z -> 3 * y * z) 5 9
= (\z -> 3 * 5 * z) 9
= 3 * 5 * 9

This might also raise another question about the order of evaluation of the multiplication operator (*). In our case (*) is left associative:

Prelude> :info (*)
class Num a where
  ...
  (*) :: a -> a -> a
  ...
    -- Defined in `GHC.Num'
infixl 7 *

That is, your 3 * 5 * 9 actually is (3 * 5) * 9.

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
  • functions are opaque so there's probably no substitution in the lambda body. (of course this is all just for illustration, who knows how it is actually compiled). personally, I like showing this with the `let`-based re-writes: `multThree 3 5 9 = (\x -> \y -> \z -> x * y * z) 3 5 9 = let {x=3} in (\y -> \z -> x * y * z) 5 9 = let {x=3} in let {y=5} in (\z -> x * y * z) 9 = let {x=3} in let {y=5} in let {z=9} in x * y * z = let {x=3} in let {y=5} in let {z=9} in 15 * z = let {x=3} in let {y=5} in let {z=9} in 135 = 135`. – Will Ness Sep 09 '21 at 14:26
1

You forgot the lambdas, otherwise your interpretation is correct:

((multThree 3) 5) 9 =
((\y z -> 3*y*z)5)9 =
(\z -> 15*z)9 =
15*9
= 135

In fact, multThree 3 is the function that expects y and z, and returns 3*y*z. We write that as \y z -> 3*y*z.

Similarly multThree 3 5 is the function that expects only z and returns 3*5*z. We write that as \z -> 3*5*z.

Finally multThree 3 5 9 is no longer a function, 3*5*9.

chi
  • 111,837
  • 3
  • 133
  • 218