@kha Trying again :)
I started using the prefix `f` for the `Fin` version (e.g., `fswap` and
`fswapAt`). So, it seemed natural to use the prefix `f` for the `Fin`
versions of `get` and `set`.
BTW, is it too crazy to use `a[i]` (without spaces) as notation for
`a.get i`? The constraint is to make sure `f a [i]` is not ambiguous.
That is, `f a[i]` is `f (a.get i)` and `f a [i]` is `f a (i::nil)`.
This is doable with the new parser.
Then, we could have `a[i]` as notation for `a.fget i` if `i` is a `Fin`,
and `a.get i` if `i` is `Nat`.
Similarly, `a[i := v]` would be notation for `a.fset i v` if `i` is
`Fin`, and `a.set i` if `i` is `Nat`.
It would also be awesome to have
```
let a[i] := v in
e
```
as notation for
```
let a := a[i := v] in
```
The `mforeachAux` function was keeping two references to the array
because it was implemented using `miterate a ⟨a, rfl⟩ ...`
Thus, we would have to allocate a new array even if `a` was not shared.
Another issue is that when invoking `x ← f i v`, the array would still
have a reference to `v`, and consequently `RC(v) > 1`, and `f` would not
be able to perform destructive updates to `v` or reuse its memory cell.
Thus, I removed `mforeach` (we only used it to implement `hmap`: the
homogeneous map), and implemented a new `hmap` which makes sure
destructive updates can be performed modulo the issue with float `let`
inwards I described in the previous commit.
@kha I found the problem described in the previous commit when I was
using `Array.hmap`. If we use `Array`s to implement `Syntax` as we discussed,
then a `hmap` that does not prevent destructive updates from happening is
a must-have. Otherwise, any benefit we get from using `Array`s instead
of `List`s is gone.
@kha I renamed the homogeneous `map` to `hmap`, and added the
heterogeneous one as `map`. As soon as we add user-defined rewriting
rules, we will be able to replace `map` with `hmap` whenever the types
are the same.
Old `Nat.repeat` => `Nat.for`
Old `Nat.mrepeat` => `Nat.mfor`
New `Nat.repeat` has type
```
def repeat {α : Type u} (f : α → α) (n : Nat) (a : α) : α :=
``
`List.repeat` => `List.replicate` (like in Haskell)
Avoid weird `ℕ` in List library
The array read and write operations are now called:
- "Comfortable" version (with runtime bound checks):
`Array.get` and `Array.set` like OCaml.
It is also consistent with `Ref.get` and `Ref.put`,
and `get` and `set` for `MonadState`.
- `Fin` version (without runtime bound checks):
`Array.index` and `Array.update` like in F*.
- `USize` version (without runtime bound checks and unboxing):
`Array.idx` and `Array.updt`.
cc @kha
Without these annotations, Lean will timeout when trying to synthesize
the type class instance `decidable_eq uint32`. The type class resolution
problem will produce the unification problem:
```
decidable (@eq uint32 a b) =?= decidable (@eq usize ?x ?y)
```
which Lean tries to solve by assigning `?x := a`.
During the assignment, the types of `?x` and `a` are unified with "full
force". Thus, we get the constraint
```
usize_sz =?= uint32_sz
```
which will take forever to be solved when peforming the computation in
unary arithmetic.
Remark: this commit also makes sure that `type_context` will not unfold
irreducible definitions when trying to unify/match the types.
The new test `type_class_performance1.lean` exposes the problem fixed
by this commit.