-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recursive types #154
Comments
Some additional thoughts:
|
@byorgey the equirecursive types look cool, but the paper about them in F-omega system seems a bit too powerful for Swarm. 😮 I like the If I understand correctly, it is not even blocked on type synonyms (#153), though it would be annoying to use without them. But what would the types of functions change to? 🤔 |
Well, we don't have System F-omega, just System F.
Agreed.
What do you mean? Why would the types of functions change? |
Well if |
Well, regardless of whether |
Hmm. I'm thinking about how to implement type equality checking with equirecursive types, since it's the most interesting to me. It seems tricky though. We need to change the implementation of the |
Not to miss an opportunity for puns, might I suggest harvesting "pecans" to unlock use of "Cons" cells? |
Rereading the discussion above, I think equirecursive types would be too complicated. We should just stick with simpler isorecursive types with explicit |
I took my comment as a challenge and started working on this; my initial explorations are on the
|
…1802) Closes #1661; towards #154. `unification-fd` is very powerful, and extremely fast, but it was written a long time ago and its age shows. It was not possible to incorporate it into our effects system in a nice way, necessitating the use of concrete monad transformers in the typechecking code. In addition it is impossible to customize, and we have been contemplating new type system features such as #153 and #154 that turn out to require hooking into the way the unification algorithm works (see #154 (comment) for more details). This PR thus removes the dependency on `unification-fd` and implements our own version of unification. It is not quite as fast as `unification-fd` but I consider the slowdown acceptable in order to gain e.g. recursive types. And of course there is also room to optimize it. The custom `UTerm` from `unification-fd` is replaced with the standard `Free` (free monad) construction from the `free` package, and the custom `Fix` from `unification-fd` is replaced with the one from `data-fix`. We also get rid of the `unifyCheck` function, which used to be a quick short-circuiting way to check whether two types definitely did not unify or might unify, allowing us to give better error messages more quickly. Now, the `=:=` unification operator itself just does this.
Implements recursive types. Example: ``` tydef List a = rec l. Unit + a * l end def nil : List a = inl () end def cons : a -> List a -> List a = \x. \l. inr (x, l) end def foldr : (a -> b -> b) -> b -> List a -> b = \f. \z. \xs. case xs (\_. z) (\c. f (fst c) (foldr f z (snd c))) end def map : (a -> b) -> List a -> List b = \f. foldr (\y. cons (f y)) nil end ``` As discussed at #154, this uses the syntax `rec x. F(x)` to define the type `x` which is a solution to `x = F(x)`. However, unlike the discussion there, I ended up going with *equirecursive* types (so a recursive type is *equal to* its unfolding). For example, as you can see above, if we have a value of type `List a` (defined as `rec l. Unit + a * l`), then it actually has the equivalent type `Unit + a * List a`, so we can simply do a `case` on it, without having to `unroll` first. This actually turned out to be *easier* to implement (and it is cooler). There are multiple built-in functions that conceptually return a list but currently do something different (like return a fold, or take an index and return a single element, etc.) We should consider changing them to actually return lists, but that should definitely be in a separate PR. Closes #154.
Add a
rec
(likeFix
) operator which would open the door to any recursive data structure, like list, set or map.This would also add two reserved function names:
roll : f (rec f) -> rec f
unroll : rec f -> f (rec f)
Example from IRC (lets assume
a + b = L a | R b
, and functionsgetLeft
,getRight
):Special case for
list
As the list is particularly useful it might be provided to players early and internally stored as
rec
, with special rules for parsing and pretty-printing. Something like[1,2,3]
and hardcoding the type synonymlist
.In gameplay, this could be introduced as a "stable form" of something more advanced. Having the appropriate device installed would load the basic list functions into the dictionary. Curious players could then type
> cons
and wonder what it will later be useful for. 🙂Related:
rec
applied to correct typesstreamf a = (int, () -> a)
)run
toimport
and typecheck it properly #495 (so less savvy players couldload data.list.sw
which they would find on Wiki)The text was updated successfully, but these errors were encountered: