Some sub-expressions of thunks are re-evaluated several times
yannham opened this issue · comments
Describe the bug
During unrelated tests, I noticed that some expressions which should be only evaluated once given the lazy evaluation model of Nickel are actually re-evaluated potentially many time. This bug hits in particular thunks which are in weak head normal form from the beginning, such as arrays or records.
To Reproduce
Put a computation inside an array and that array inside a thunk, and request the evaluation of the element several times:
nickel> let trace_eval = fun x => std.trace "evaled!" x in let y = [trace_eval null] in [std.array.elem 0 y, std.array.elem 0 y]
std.trace: evaled!
std.trace: evaled!
[ false, false ]
Expected behavior
I expect that the expression trace_eval null
, part of the thunk y
, is only evaluated at most once:
nickel> let trace_eval = fun x => std.trace "evaled!" x in let y = [trace_eval null] in [std.array.elem 0 y, std.array.elem 0 y]
std.trace: evaled!
[ false, false ]
Environment
- OS name + version:
- Version of the code:
Additional context
The issue should to be related to the elimination of generated variables, which caused some invariant previously held to become false. In particular, the function Thunk::should_update
, which decides if a thunk is worth updating, is at fault. A fix is on its way.