-
Notifications
You must be signed in to change notification settings - Fork 412
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
Instantiating constructor into application position does not work intuitively #64
Comments
The rule for nullary constructors What's the reason for this rule? HOW.md doesn't seem to provide explanation. My guess is that having all constructors be applications (of arity ≥0) makes implementing rewrite rules somehow easier, but I don't want to assume. |
That isn't an issue, but that's definitely confusing for newcomers. Global definitions must be seen as functions, and they need to be "called" to retrieve the right-hand side. So, in your example, Uncurried (correct)
Curried (correct)
Curried (wrong)
Uncurried (wrong)
Why not make everything curried?Uncurried functions are much faster. HVM is a global graph-rewrite machine that replaces left-hand sides by right-hand sides. Because of that, and unlike Haskell (that compiles functions to bytecode), HVM functions must alloc the right-hand side whenever they are called. This is required for fusion, beta-optimality, parallelism, etc. But that also means a definition like:
Will alloc more data than a definition like:
Because the right-hand sides are smaller. Splitting otherwise big function bodies into small function bodies through a Haskell-like equational notation is one of the main reasons HVM is much faster than previous optimal evaluators, so, if everything was curried, we'd get a substantial real-world impact on performance. A user-facing language that compiles to HVM (like Kind, Haskell, etc.) may still be fully curried, though, and use n-ary functions as a compile-time optimization, breaking |
I'm fine with that; it makes sense to me that |
@Quelklef hmm what would |
Okay, I poked around Consider the two HVM expressions These two expressions parse very distinctly, something like The expressions appear very similar, and I had assumed that they would parse more similarly. Something like, The crucial difference here is that I've given constructor names their own ast node type This would, of course, brings about difficulties regarding currying. Rewrite rules like Conceptually, constructors and λ-terms are similar: with both the definition They could, in theory, be unified, by giving constructor names an AST node, but I leave that decision to you. If they are to be kept distinct, I would suggest that |
Yep, they could be unified, but then the optimizations above wouldn't apply; the de-unification is what made HVM so fast to begin with. Initially they had different syntaxes (constructors used |
FWIW I think the |
This HVM code reduces
(Main)
to(Pair ((Succ) 0) 1)
. I would intuitively expect(Pair 1 1)
.My understanding for this is that in
(App Succ 0)
, the expressionSucc
is actually shorthand for(Succ)
, so we have(App (Succ) 0)
which reduces to((Succ) 0)
which does not reduce.Would this be considered an issue, or just a gotcha for newcomers?
The text was updated successfully, but these errors were encountered: