Question 1 @ 2024-11-19 18:03
Assuming that our test
tool can catch these errors, which of the
following tests would show that our language is actually lazy?
(Note: multiple choice)
-
(test (run "{{fun {x} {/ 9 0}} 5}")
=error> "division by zero") -
(test (run "{{fun {x} 5} {/ 9 0}}")
=error> "division by zero") -
(test (run "{{fun {x} {/ 9 0}} 5}")
=> 5) -
(test (run "{{fun {x} 5} {/ 9 0}}")
=> 5) - There is no way to test for actual laziness because of strictness rules
- It depends on whether the language is call-by-need or -by-name
Question 2 @ 2024-11-19 18:05
In the previous question, there was an assumption:
Assuming that our
test
tool can catch these errors, […]
Is that assumption needed? Why?
(Remember: Choose the best answer.)
- There is no need for it.
-
It’s only useful as a reminder for how
=error>
works. -
It’s needed because we must assume that
test
is implemented correctly. - It’s needed because we embed Racket’s arithmetics.
-
It’s needed because we embed Racket’s arithmetics, so
=error>
is actually useless.
Question 3 @ 2024-11-19 18:07
In the same question still, we know that we could replace {/ 9 0}
with
the omega combinator: {{fun {x} {x x}} {fun {x} {x x}}}
.
But we also know that to make a distinction between a lazy and an eager language, we need to somehow involve side-effects.
How do settle these two things?
- Tricky/bogus question: we do not have combinators in our language.
- Tricky/bogus question: we do not need to involve side-effects.
- An infinite loop is apparent to us when “enough time passed”, so it is a form of a side-effect.
- This involves an infinite loop, which is actually the halting problem, which means that the assumption underlying the question is wrong.
- We cannot settle them! Our implementation is naive, so it cannot handle such tests.
Question 4 @ 2024-11-19 18:10
What is the purpose of calling strict
on (eval* fun-expr)
in the
following Sloth implementation bit:
(define fval (strict (eval* fun-expr)))
(define arg-vals (map eval* arg-exprs))
(cases fval
...)]
-
The
strict
call is actually what makes the language lazy. - Sloth is lazy, but function calls are always eager.
-
Function calls require an actual function value, making it be a
“strictness point”, implemented using
strict
. -
We’ve seen that the simple lazy evaluation which
eval*
implements is inefficient, so we usestrict
to avoid repeating the same computations. -
It’s not needed! We just added
strict
to demonstrate how the language is actually lazy.
Question 5 @ 2024-11-19 18:12
In Sloth (the first lazy language we’ve implemented, without caching),
how many times does the expression {+ 1 2}
get evaluated when we run
the following code?
{bind {{y {+ x x}}}
{bind {{z {+ y y}}}
{+ z z}}}}
0…16
Question 6 @ 2024-11-19 18:14
In Slug (the second lazy language we’ve implemented, which adds
caching), how many times does the expression {+ 1 2}
get evaluated
when we run the following code?
{bind {{y {+ x x}}}
{bind {{z {+ y y}}}
{+ z z}}}}
0…16
Question 7 @ 2024-11-19 18:15
In the lazy Racket language that we’ve used, #lang pl lazy
, we can
observe the following interaction:
(list r r r))
'(53 53 53)
This shows us that #lang pl lazy
is …?
- … actually lazy.
- … not eager.
- … implemented with correct scoping rules.
- … compiled rather than interpreted.
- … implementing call-by-need vs call-by-name.
- … implementing call-by-name vs call-by-need.
- It doesn’t show anything significant.