-
-
Notifications
You must be signed in to change notification settings - Fork 173
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
Enable with
optimizations
#1052
Conversation
The motivation for this change is: dhall-lang/dhall-haskell#1960 This change to the standard gives implementations greater freedom in how they desugar a `with` expression, in order to permit more efficient implementations. The standard now also suggests a more efficient implementation to help implementation authors. This is technically a breaking change to the binary encoding of a non-normalized `with` expression, but semantic integrity checks are unaffected by this change.
This is an alternative proposal for #1050 based on a discussion with @Nadrieril |
… as permitted by dhall-lang/dhall-lang#1052
Here is the matching change to the Haskell implementation: dhall-lang/dhall-haskell#1993 |
Could you add a few normalization and typeckecking tests? Right now the feature is essentially untested if I'm following correctly |
@Nadrieril: There are type-checking and normalization tests for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’d like some time to test this with dhall-golang and feed back, not sure when I’ll get to it but can I at least request a hold on merging of a week to give me a chance?
@philandstuff: Yeah, I'm not in a rush |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is basically great 👍
A couple of smallish things:
Use of shift
I basically agree with @Nadrieril in #1050 (comment) that shift
is an artefact of the standard but not necessary in an implementation. Currently dhall-golang doesn't have a shift
. This feature nudges implementations towards a shift
-based implementation of with
-desugaring, but my leanings are more towards implementing with
as a first-class term, not as a desugaring.
The current dhall-golang implementation is here: https://github.com/philandstuff/dhall-golang/compare/std-pr-1052-with but I'm planning to directly implement typechecking and evaluation on with
expressions, and not do it via a desugaring step.
That said, there's nothing in this PR that prevents me doing that. The tests will still pass.
Test coverage
We don't have any typechecking tests for compound paths in a with
(such as r with x.y = v
). Might I suggest:
{- WithNestedA.dhall -}
{- This test illustrates that the `with` keyword is permitted to override
existing fields nested within a child record
-}
{ a = { p = 2, q = "hi" }, b = 5.6 } with a.p = True
{- WithNestedB.dhall -}
{ a : { p : Bool, q : Text }, b : Double }
@philandstuff: The main reason for standardizing in terms of a desugaring is because the type-checking and normalization judgments directly on |
… as permitted by dhall-lang/dhall-lang#1052
I found it confusing to implement the recent `with` optimizations (#1052) because `with` expressions are currently neither pure sugar nor first-class expressions. Also, there is arguably still scope for pathological behaviour, since an abstract function like \(r : {a : {b : {c : Natural}} }) -> r with a.b.x = 1 with a.b.y = 2 will be evaluated to a function which potentially evaluates `r` 6 times (in an implementation which does not evaluate arguments before passing them to a function). This commit defines type inference and beta-normalization for `with` expressions directly, rather than via a desugaring step. As a side-effect, desugaring of abstract `with` expressions no longer happens; they are left as plain `with` expressions. This is a breaking change. There is another consideration, which is there are currently a number of simplifications for right-biased record merge expressions which the current `with`-desugaring can piggyback on. For example, currently: (e with k = v).k evaluates to `v`, because of the simplification of expressions of the form `(l // { k = v, rs... }).k`. This commit does not attempt to preserve those simplifications, but we could introduce some `with`-simplifications in later commits if desired.
I found it confusing to implement the recent `with` optimizations (#1052) because `with` expressions are currently neither pure sugar nor first-class expressions. Also, there is arguably still scope for pathological behaviour, since an abstract function like \(r : {a : {b : {c : Natural}} }) -> r with a.b.x = 1 with a.b.y = 2 will be evaluated to a function which potentially evaluates `r` 6 times (in an implementation which does not evaluate arguments before passing them to a function). This commit defines type inference and beta-normalization for `with` expressions directly, rather than via a desugaring step. As a side-effect, desugaring of abstract `with` expressions no longer happens; they are left as plain `with` expressions. This is a breaking change. There is another consideration, which is there are currently a number of simplifications for right-biased record merge expressions which the current `with`-desugaring can piggyback on. For example, currently: (e with k = v).k evaluates to `v`, because of the simplification of expressions of the form `(l // { k = v, rs... }).k`. This commit does not attempt to preserve those simplifications, but we could introduce some `with`-simplifications in later commits if desired.
I found it confusing to implement the recent `with` optimizations (#1052) because `with` expressions are currently neither pure sugar nor first-class expressions. Also, there is arguably still scope for pathological behaviour, since an abstract function like \(r : {a : {b : {c : Natural}} }) -> r with a.b.x = 1 with a.b.y = 2 will be evaluated to a function which potentially evaluates `r` 6 times (in an implementation which does not evaluate arguments before passing them to a function). This commit defines type inference and beta-normalization for `with` expressions directly, rather than via a desugaring step. As a side-effect, desugaring of abstract `with` expressions no longer happens; they are left as plain `with` expressions. This is a breaking change. There is another consideration, which is there are currently a number of simplifications for right-biased record merge expressions which the current `with`-desugaring can piggyback on. For example, currently: (e with k = v).k evaluates to `v`, because of the simplification of expressions of the form `(l // { k = v, rs... }).k`. This commit does not attempt to preserve those simplifications, but we could introduce some `with`-simplifications in later commits if desired.
* Implement `with` directly rather than via desugaring I found it confusing to implement the recent `with` optimizations (#1052) because `with` expressions are currently neither pure sugar nor first-class expressions. Also, there is arguably still scope for pathological behaviour, since an abstract function like \(r : {a : {b : {c : Natural}} }) -> r with a.b.x = 1 with a.b.y = 2 will be evaluated to a function which potentially evaluates `r` 6 times (in an implementation which does not evaluate arguments before passing them to a function). This commit defines type inference and beta-normalization for `with` expressions directly, rather than via a desugaring step. As a side-effect, desugaring of abstract `with` expressions no longer happens; they are left as plain `with` expressions. This is a breaking change. There is another consideration, which is there are currently a number of simplifications for right-biased record merge expressions which the current `with`-desugaring can piggyback on. For example, currently: (e with k = v).k evaluates to `v`, because of the simplification of expressions of the form `(l // { k = v, rs... }).k`. This commit does not attempt to preserve those simplifications, but we could introduce some `with`-simplifications in later commits if desired. * small tweaks * oops, remove duplicate alpha-normalization rule * Update standard/beta-normalization.md Co-authored-by: Gabriel Gonzalez <Gabriel439@gmail.com> * Update standard/type-inference.md Co-authored-by: Gabriel Gonzalez <Gabriel439@gmail.com> * fix type inference rule as caught by @Nadrieril * better mnemonic variable names as caught by @Gabriel439 * Allow creation of intermediate records also tidy up the judgments a bit, add tests for the new judgments, remove tests for the old desugaring behaviour. * Update standard/type-inference.md Co-authored-by: Gabriel Gonzalez <Gabriel439@gmail.com> * Update standard/type-inference.md Co-authored-by: Gabriel Gonzalez <Gabriel439@gmail.com> * Add a test for partially-abstract `with` expressions This caught a bug in dhall-golang. Co-authored-by: Gabriel Gonzalez <Gabriel439@gmail.com>
The motivation for this change is:
dhall-lang/dhall-haskell#1960
This change to the standard gives implementations greater freedom
in how they desugar a
with
expression, in order to permit moreefficient implementations. The standard now also suggests a more
efficient implementation to help implementation authors.
This is technically a breaking change to the binary encoding of
a non-normalized
with
expression, but semantic integrity checksare unaffected by this change.