1

mult is defined as a curried function:

mult    ::  Int ->  Int ->  Int
mult    x   =   \y  ->  x   *   y

In mult (1+2) (2+3),

  • what are the redex's. and are they mult(1+2), 1+2 and 2+3?
  • What is the outermost redex, and is it 2+3?

Innermost evaluation works on the expression as following, according to Programming in Haskell by Hutton:

mult    (1+2)   (2+3)
= { applying    the first   +   }
mult    3   (2+3)
= { applying    mult    }
(\y ->  3   *   y)  (2+3)
= { applying    +   }
(\y ->  3   *   y)  5
= { applying    the lambda  }
3   *   5
= { applying    *   }
15

How does outermost evaluation work on mult (1+2) (2+3)? Does outermost evaluation works as the following?

mult (1+2) (2+3)
= mult (1+2) 5
= (\y -> (1+2) * y) 5
= (1+2) * 5  // Is (1+2) evaluated before (1+2) * 5, because builtin function "*" is strict, i.e. application of builtin function always happen after evaluation of its args?
= 3*5
= 15

Thanks.

Tim
  • 1
  • 141
  • 372
  • 590

2 Answers2

1

The outermost redex in mult (1+2) (2+3) i.e.

          mult
       /        \
      +          +
    1   2      2   3

is mult x y where x = (1+2) and y = (2+3).

There are two inner redexes, (1+2) and (2+3). The leftmost innermost redex is thus (1+2).

Reducing by the leftmost innermost redex proceeds as follows:

mult (1+2) (2+3)
=
mult 3 (2+3)
=
mult 3 5
= {- mult x = \y -> x * y -}
(let x = 3 in (\y -> x * y)) 5
=
let x = 3 in let y = 5 in x * y
=
3 * 5
=
15

Reducing by the topmost redex proceeds as follows:

mult (1+2) (2+3)
= {- mult x = \y -> x * y -}
(let x = (1+2) in (\y -> x * y)) (2+3)
=
let x = (1+2) in let y = (2+3) in x * y
=
(1+2) * (2+3)
=
3 * (2+3)
=
3 * 5
=
15
Will Ness
  • 70,110
  • 9
  • 98
  • 181
1

Write down the parse tree:

         o
       /   \
     o       o
    / \     /|\
mult   o   2 + 3
      /|\
     1 + 2

(For simplicitly I'm treating the binary infix + operators as a single application, it could have been ((+) 1) 2 as well)

Now the outermost function application is that of mult (1+2) to the argument 2+3, but it's not reducible because the function is not a single value but an application itself. We have to evaluate that first:

(mult (1+2)) (2+3)
((\x->\y->x*y) (1+2)) (2+3) -- the value that `mult` refers to
(\y->(1+2)*y) (2+3) -- evaluate the application of `\x->`

Now we can evaluate the root function application:

(1+2) * (2+3) -- application of `\y->`

Now the outermost expression is the *, but as you know these integer operators are strict so they need to evaluate their arguments first (left-to-right, IIRC):

3 * (2+3)
3 * 5
15
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks. What is the definition of a parse tree? In "Compilers: Principles, Techniques, and Tools", in a parse tree, a operator or function node has its arguments as its child nodes. For exampe `mult (1+2) (2+3)` will have a parse tree in https://stackoverflow.com/a/57028299/156458 – Tim Jul 14 '19 at 20:45
  • @Tim Yes and no. The thing is that in Haskell, whitespace is an operator: it applies the lhs function to the rhs argument. That's the reason why we can write `mult 3 5` which has the same parse tree as the explicit `(mult 3) 5` - it's like `call(call(mult, 3), 5)` in other languages. – Bergi Jul 14 '19 at 21:00
  • Thanks. Could you explain the meaning of "outermost" and "leftmost" (in case there are several "outermost")? Also the meaing of "innermost", and how do you use innermost evaluation on the expression? – Tim Jul 14 '19 at 21:08
  • @Tim No, there is only one outermost function application: the one that is the root of the parse tree. There are several innermost ones (basically those directly above the leaves of the tree), and one of them is the most-on-the-left one. – Bergi Jul 14 '19 at 21:11
  • What are some common "other languages" which have `call`? – Tim Jul 14 '19 at 21:13
  • @Tim No, I just meant the function call syntax with parenthesis as is common in other languages, and I spelt out Haskells "`call` operator" explicitly using that syntax – Bergi Jul 14 '19 at 21:20
  • `1 + 2` is the only innermost redex. and isn't `2 + 3` the only outermost redex? – Tim Jul 14 '19 at 21:21
  • @Tim No, what makes you think that? – Bergi Jul 14 '19 at 21:24
  • the outermost function application is that of mult (1+2) to the argument 2+3, but it's not reducible. mult (1+2) and 2+3 are at the same level of outerness, 2+3 is reducible, I am not sure about mult(1+2), because it isn't immediately reducible althouhg is left to 2+3. Could you explain more? – Tim Jul 14 '19 at 21:53
  • @Tim both `(1+2)` and `(2+3)` are at the same depth level in the parse tree. that makes them be equally *inner* expressions. it so happens both have no sub-expression, so they both are inner- *most*. One is on the left of the other, so it is also the leftmost (i.e. `(1+2)`). The top(most) node in the tree is `mult _ _`. It has the smallest depth among all subexpressions (namely, 0). – Will Ness Jul 15 '19 at 08:36
  • @Tim Being outermost doesn't require being reducible. – Bergi Jul 15 '19 at 09:59
  • and of course it is reducible: replacing `mult` with its definition we get an application of a lambda function and an argument `(1+2)`. – Will Ness Jul 15 '19 at 11:06
  • @WillNess In my answer I made two single-argument applications, instead of applying `mult` to two arguments at once. Is that wrong? – Bergi Jul 15 '19 at 11:11
  • 1
    I assumed it's more about lambda calculus, not Haskell specifically. I think I too made single-argument applications in my answer, it's just that the parse tree is different than in your answer. – Will Ness Jul 15 '19 at 11:28