Re-introduce let-declarations #42
Labels
No labels
blocked
blocker
bug
c
codegen
dependencies
discussion
documentation
duplicate
enhancement
good first issue
help wanted
in progress
invalid
javascript
lexer/parser
llvm
macroexpander
performance
priority:high
priority:low
priority:normal
question
triage
typechecker
webassembly
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: samvv/bolt#42
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Currently,
let
-declarations have been split up into function declarations (using the keywordfn
) and variable declarations (using the keywordlet
). This solves a few issues, but is far from ideal. Ideally, we'd like to keep the syntax as simple as possible and as close as possible to what Haskell does.The original issue resulted from the fact that as a strict language, we would like to make the distinction between an ordinary variable declaration (such as
let foo = 42
) and functions with no argument (with type() -> Int
for example). Imagine for a moment thatfoo
did an expensive calculation and the user didn't want to run this calculation right away. Without the split, there was no way of saying that the computation should be delayed.Solution
In this new proposal, we address some of the confusion regarding strict/lazy evaluation, typing, and the difference between function declarations and variable declarations.
A first observation is that the way the program is typed should have no effect on the way it is evaluated, be it with the exception of type classes. Therefore, whether
foo
is typed as() -> Int
orInt
should make no difference. As a consequence, the special parameterlessTArrow
type that came with the initial design has no real use.A second insight is that users always can defer the computation of a variable, even in the context of strict evaluation and currying. They just have to declare a variable
let foo = \() -> 42
and call it with the unit tuple. We can abstract away this solution to something likelet foo = thunk 42
and force execution with e.g.foo!
. Alternatively, we could introduce thelazy
keyword and require the variable to be only computed if it has been referenced.Implementation Strategy
let x : Foo
) be a variable declaration. If there are any parameters such aslet x a b : Foo
, then that is an error that should be reported.let x = 1
) be treated like a function, even if there are no parameters. In that case, it just so happens to not have aTArrow
.let
-declaration to be a variable. Parameters are invalid.mut
makes the declaration automatically be a variable declaration. Parameters are invalid.Remarks
TArrow
type. The solution usingthunk
as described in the previous section will always generate aTArrow
, while variable declarations don't need to hold an effect and simply contribute to the effect of their parent declaration.