lean4-htt/library/init/lean
Leonardo de Moura 261dc999d0 refactor(frontends/lean/elaborator): mark thunk as opaque, and thunk A to A is now a coercion
@kha I was working in the new declaration type and using tasks there.
Since we don't have tasks yet in Lean, I decided to start refactoring
the `thunk` type. I defined it as:

```
-- TODO(Leo): mark as opaque, it is implemented by the new runtime
structure thunk (α : Type u) : Type u :=
(fn : unit → α)

def thunk.pure {α : Type u} (a : α) : thunk α :=
⟨λ _, a⟩

def thunk.get {α : Type u} (t : thunk α) : α :=
t.fn ()
```

The idea is to use the runtime primitives to implement them.
Then, I realized the support for `thunk`s in the elaborator are quite
hacky. Given `f x`, if `f`'s domain has type `thunk A`, we elaborate
`f x` as `f (fun _, x)` even if `x` has type `thunk A`.
This is quite bad, for example, suppose we have
```
def f (x : thunk A) := ...
```
Then, the following definition is type incorrect.
```
def g (x : thunk A) := f x
```
and we are forced to write
```
def g (x : thunk A) := f (x ())
```
The term `f (x ())` will be elaborated as `f (fun _, x ())` and an
unnecessary closure is created at runtime.

This mechanism inherited from Lean 3 is also incompatible with the
new thunk definition. Given `x : thunk A`, I want to write `x.get`
to retrieve the value instead of `x ()` as in Lean 3.
However, `x.get` expands into the nonsensical `(fun _, x).get`.

So, I decided to view the mapping `A` to `thunk A` as a "coercion".
I used double quotes, because it is a macro instead of a function.
If it were a coercion, then we would be using `thunk.pure` to coerce
values but this is not we want most of the time.
For example, given `f : thunk A -> B` and a term `t : A`, when we write
`f t`, we want it to be converted into `f (fun _, t)` instead of
`f (thunk.pure t)` which would eagerly compute `t`. The transformation
`t` into `fun _, t` is syntactic.
We cannot implement it using type classes. I implemented it as
a hard-coded extra case like the one from `Prop` to `bool`.
We can also add a coercion from `thunk A` to `A` to avoid the `.get`.

That being said, I had a few breakages in the code base since we only
use coercions when the given and expected type do not contain
metavariables.
2018-08-21 15:27:51 -07:00
..
core feat(library/init/lean/core): define core language 2018-05-18 15:35:42 -07:00
ir feat(library/derive_attribute): temporary, hacky C++ implementation of @[derive] 2018-08-01 18:44:23 -07:00
parser refactor(frontends/lean/elaborator): mark thunk as opaque, and thunk A to A is now a coercion 2018-08-21 15:27:51 -07:00
config.lean feat(library/init/lean): add lean.closure_max_args 2018-05-13 08:40:46 -07:00
declaration.lean chore(library/init/lean/declaration): add new declaration type 2018-08-21 10:13:16 -07:00
disjoint_set.lean feat(library/init/lean/ir): add elim_phi function 2018-05-06 10:07:44 -07:00
expr.lean chore(library/init/lean/expr): document mvar new design 2018-06-22 15:06:36 -07:00
format.lean refactor(frontends/lean/elaborator): mark thunk as opaque, and thunk A to A is now a coercion 2018-08-21 15:27:51 -07:00
kvmap.lean feat(library/init/lean): add kvmap 2018-06-15 16:05:11 -07:00
level.lean feat(library/init/lean/level): missing functions 2018-05-22 10:49:24 -07:00
name.lean chore(library/equations_compiler/util): disable generation of equational lemmas 2018-06-12 13:03:25 -07:00
name_mangling.lean feat(library/init/lean/parser/parsec): add custom error message type 2018-07-27 14:29:50 -07:00
options.lean feat(library/init/lean): add kvmap 2018-06-15 16:05:11 -07:00
pos.lean refactor(library/init/lean/trace): avoid init.meta import 2018-05-17 14:25:12 +02:00
trace.lean refactor(frontends/lean/elaborator): mark thunk as opaque, and thunk A to A is now a coercion 2018-08-21 15:27:51 -07:00