Question 1 @ 2024-02-27 18:33
When using a recursive binder like letrec
or our rec
, what is the
advantage of restricting its usage to binding only function values?
-
None,
letrec
(orrec
) should be used on all functions. -
None, it’s just an idiomatic requirement to bind all functions recursively.
-
The evaluator can assume that the binding is recursive, avoiding the need for more code when it isn’t.
-
It increases efficiency to know in advance that the value is a function.
-
When evaluating a
fun
expression, the body is evaluated first, therefore avoiding infinite loops. -
When evaluating a
fun
expression, there is no evaluation of the body, so self references there would be safe.
Question 2 @ 2024-02-27 18:35
Is there ever any use for a non-function form in a named expression in a
recursive letrec
/ rec
binder?
-
It could be used when a function value is contained in an expression rather than being the whole expression.
-
Some recursive value definitions are useful too, like an AST type that is defined in terms of itself.
-
It’s useful when a function is made in a way other than a
lambda
/fun
expression, as in currying or using H.O. functions likecompose
. -
No – restricting recursive binders to function forms don’t affect what you can do with the language.
Question 3 @ 2024-02-27 18:38
Is there ever any reason to use a plain let
for a function value?
(Or with
, or even an internal define
in idiomatic Racket)
-
Since function bodies are not evaluated immediately, there is never any difference between
let
andletrec
. -
When there’s no need for a recursive function,
let
makes it possible to compile function calls more efficiently. -
It’s useful to use
let
when we want to implement the Y combinator itself. -
It can be used to “wrap” functions in a local part of the code.
-
It is a bad idea since it can lead to name shadowing.
Question 4 @ 2024-02-27 18:40
Here is a verbose implementation of a xor
function in Schlac:
What would be valid simplification of it?
-
(define xor (lambda (a b) (a (b a b) b)))
-
(define xor (lambda (a b) (a (b b a) (b a b))))
-
(define xor (lambda (a b) (a (not b) b)))
-
(define xor (lambda (a b) (a b #f)))
- There is no way to simplify the above expression.
Question 5 @ 2024-02-27 18:43
What does (#t #f #t 1 2)
reduce to using our Schlac encodings?
-
#t
-
#f
- 1
- 2
-
Error, since we never defined
#t
or#f
in our encodings -
Error, since booleans are strict and always require an
if
- Error, since we passed too many arguments to a function
- Error, since we call a non-function value
Question 6 @ 2024-02-27 18:46
What is the core need for a practical implementation of recursion?
-
An environment that can point to itself.
-
An environment that can be mutated instead of extended.
-
Using Racket’s
letrec
. -
Using local definitions in function bodies.