# Class 21: Functional Programming, Concluded

Back to FP, Continued. On to Introduction to Logic Programming.

Held Friday, March 12

Summary

• Exam 2 distributed. Due Friday, March 19.

Contents

Handouts

Notes

• Exam 2 is now ready.
• Next week, we'll be discussing logic programming. You should read chapter 11 for Monday.
• I was sorry to see so few of you at yesterday's convocation. The speaker presented many interesting applications of the Fibonacci sequence.
• Are there any questions on assignment 4?

## Factorial in FP

• The best way to understand FP is to apply it in some situations.
• Instead of working with the definition in the paper, we'll try to build it up ourselves.
• We'll build both recursive and iterative versions, to strengthen our understanding of the language.

### Recursive

• Recursively, we think of factorial as something like ``if the argument is 0, then use the value 1; if it's anything else, then multiply that number by the result of recursing on ...''
• We will clearly need a conditional (since that's how we start), the ability to test for 0, the ability to return 1, and the ability to tie together multiplication and recursion (and much more).
• First step, just the conditional
• `Def fact = eq0 -> one ; recurse `
• Note that there are no arguments in FP, so we'll need to think about how to handle that problem.
• Next step, define `one`
• A function that returns 1 (yes, it's a function and not a value)
• `Def one = constant 1`
• Constant is written with a bar in the paper and `%` in our implementation of fp.
• In the fp interpreter we'll use, write, `{one %1}`
• Next step, define `eq0`
• Hmm ... can't refer directly to its arguments, can't use values?
• Need to make the pair ("my argument",0)
• Ah, that's why we need `id`
• We also need constant function of 0
• After making the pair, we still need to get a truth value, but that's pretty easy.
• `Def eq0 = = @ [id,%0]`
• `@` is function composition
• `[...]` if function construction
• In the fp interpreter we'll use, write, `{eq0 = @ [id,%0]}`
• For the recursive part, we'll need to define `sub1`
• Fairly similar to the last part
• `Def sub1 = - @ [id,%1]`
• In the fp interpreter we'll use, write, `{sub1 - @ [id,%1]}`
• All that's left is the full recursive part
• `* @ [id, fact@sub1]`
• Putting it all together
• `{fact (eq0 -> %1 ; * @ [id, fact@sub1])}`

### Iterative

• Can we rewrite this iteratively, as a loop?
• Sure, but it's a little bit harder.
• (As you know, functional languages encourage recursion :-)
• We have multiple loops we can write.
• We can multiply from N down to 1.
• We can multiply from 1 up to N.
• We'll use the latter.
• If we're going to write a loop, we need to keep track of a few intermediate values (just as we do in any iterative solution to this problem)
• The current value of our ``counter'' (starts at 1)
• The current product (starts at 1)
• N (the ``input'', always the same)
• Recall that FP loops apply the same function over and over to an argument.
• Since we have multiple intermediate values, we'll need to put them into a sequence.
• So, we start our function by making a triplet
• `[%1, %1, id]`
• Each time through, we need to add 1 to the counter, multiply the product by the old value of the counter, and keep N the same. This is the body of our loop.
• To add 1 to the counter
• `+ @ [id,%1] @ 1`
• That last `1` is a selector, which extracts the first part of the tuple.
• We could also write `+ @ [1,%1] `
• To update the product-so-far
• `* @ [1,2]`
• That is, multiply the counter by the product-so-far
• To update N
• `3`
• Yes, that's a selector
• And it just selects the old value of N
• Recall that in the FP model, the body of the loop is applied to a value and then we loop again. So, since we've built this triple, the body must generate a triple
• `[+ @ [id,%1], * @ [1,2], 3]`
• How long do we keep going (assuming our input is non-negative?) As long as the counter is less than N
• `< @ [1,3]`
• Finally, we need to extract the answer.
• Let's tie it all together
• `Def itfact = 2 @ (while (<= @ [1,3]) ([+ @ [1,%1], * @ [1,2], 3])) @ [%1, %1, id]`
• `{itfact 2 @ (while (<= @ [1,3]) ([+ @ [1,%1], * @ [1,2], 3])) @ [%1, %1, id]}`

### A Simpler Technique

• Of course, both of these solutions ignore some of the intrinsic power of FP. In particular, we can take advantage of `iota`.
• Since `iota:n` gives all the numbers from 1 to n, we just want to insert multiplication between them.
• That is,
• `{newfact !*@iota}`

## Other Design Issues in Functional Languages

• Believe it or not, we've only scratched the surface of interesting design issues in functional languages. We'll quickly consider three others.

### Type Systems

• A number of functional languages (particularly ML and Haskell), have nice, polymorphic type systems.
• You can define parameterized types.
• The system can infer many types.
• The programmer can type things when it is appropriate to do so.

### Pattern Matching

• Some languages permit you to write pattern-based equations, like those in the Scheme syntax.
• For example,
```fact 0 = 1
fact n = n * fact n-1
```
• Similarly, we might even define the three core Scheme functions with
```car (cons x xs) = x
cdr (cons x xs) = xs
```
• In fact, we can even define control structures
```if True x y = x
if False x y = y
```

### Lazy Evaulation

• There are two basic evaluation strategies in functional languages (and similarly in the lambda calculus).
• In eager (innermost) evaluation, the arguments are evaluated before the function is called.
• In lazy (outermost) evaluation, the arguments are not evaluated until they are needed (in effect, an encapsulation of the arguments is passed to the function).
• For example, if we were lazily evaluating `square (plus 2 3)`, (given the defintion of `square` as
```square x = times x x
```
we might compute
```square (plus 2 3) =>
times (plus 2 3) (plus 2 3) =>
times 5 (plus 2 3) =>
times 5 5 =>
25
```
• Doing this eagerly would result in
```square (plus 2 3) =>
square 5 =>
times 5 5
25
```
• Using examples like this, many have argued that lazy evaluation is inefficient.
• However, in a pure language, it may be possible to avoid the recomputation of the duplicated argument (by remembering the relationship between the two).
• Surprisingly, lazy evaluation is required for recursive computation.
• Consider the standard factorial function,
```fact n = iif (n == 0) 1 (n * (fact (n - 1)))
```
• Let us compute the factorial of 1 using eager evaluation.
```fact 1 =>
iif (1 == 0) 1 (1 * (fact (1 - 1))) =>
iif false 1 (n * (fact (1 - 1))) =>
iif false 1 (n * (fact 0)) =>
iif false 1 (iif (0 == 0) 1 (0 * (fact (0-1)))) =>
iif false 1 (iif false 1 (0 * (fact (0-1)))) =>
iif false 1 (iif false 1 (0 * (fact (-1)))) =>
iif false 1 (iif false 1 (0 * (iif (-1 == 0) 1 (-1 * fact(-1-1))))) =>
...
```
• For this and similar cases, lazy evaluation isn't just a better idea, it's necessary.

History

• Created Tuesday, January 19, 1999 as a blank outline.
• Filled in the details on Friday, March 12. Some details were taken from the previous outline (as they had not been covered in that class). Thanks to Andrew Cody for reminding me of an alternate technique and finding some bugs in my code. The discussion of lazy evaluation was modified from one in outline 29 of CS302 98S.
• Fixed a few typos on Monday, April 5 (thanks Amartey!).

Back to FP, Continued. On to Introduction to Logic Programming.

Disclaimer Often, these pages were created ``on the fly'' with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.