Skip to content
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

Reduce indentation hell. #1147

Merged
merged 2 commits into from
Nov 8, 2022
Merged

Conversation

axch
Copy link
Collaborator

@axch axch commented Nov 7, 2022

Implement <- as syntactic sugar for continuation lambdas.

Apply it throughout the prelude to see how it looks. If this is registering as a good change, we can propagate it throughout the rest of the corpus as well.

This fixes #1137 in spirit, if not precisely as filed (i.e., this implements the generalization in the comments, not the original ask).

Fixes google-research#1137 in spirit, if not precisely as filed (i.e., this
implements the generalization in the comments, not the original ask).

Also add `Lexer.debug`, leaning on Megaparsec's `dbg`, which actually
turns out to be very helpful for debugging the concrete syntax parser.
@axch axch requested review from apaszke and dougalm November 7, 2022 16:29
@axch axch changed the title Fix indentation hell. Reduce indentation hell. Nov 7, 2022
@axch axch force-pushed the fix-intentation-hell branch from 14fb07f to 626ee4d Compare November 7, 2022 21:12
@axch
Copy link
Collaborator Author

axch commented Nov 7, 2022

Offline, @dougalm, @apaszke, and I considered changing the syntax further to add a with keyword before the binder, following Koka. We decided against for this PR, but here is a summary of the thoughts:

Option A:

with x <- ...

Pros:
A1. Used by Koka (nice as an homage, but since Koka isn't widely used, it probably doesn't matter for users).
A2. Better for nullary functions, which can omit the x <-. However, we don't have them yet, and <- ... might work fine too.
A3. <- is confusingly close to do notation (but the semantics are close too!)
A4. with makes it easier to make it an expression.
A5. with highlights that something odd is happening.

Option B: As implemented, i.e.

x <- ...

Pros:
B1. Avoids the repeated with weirdness of with x <- with_state foo (though we could rename to start_state or something).
B2. Shorter.
B3. Binders remain left-aligned as in a sequence of equations.

@axch
Copy link
Collaborator Author

axch commented Nov 7, 2022

When reading the resulting code, @dougalm and I found that type-changing wrapper functions (most commonly yield_state) get really confusing with the <- notation.

Consider

a = code
b = code
c = code
d <- yield_state something
e = code
f = code
code

You'd think that the return type would be determined by the last line, but it's actually not -- it's determined by the first yield_state that occurs in the block.

However, using with_state the same way is fine --- the only thing that with_state does to the remainder of the block is make a new mutable reference available, and then clean it up when the block exits. But since the return value of the block is forwarded unchanged, those cleanup details are a secondary consideration, and it doesn't feel confusing at all.

We therefore propose a convention, at least for the time being: The <- syntax is for functions that accept a continuation lambda but do not alter its return type; whereas if the return type is changing, use an explicit lambda and indent it.

We considered enforcing this convention with a special type-checking rule, but decided against because (i) that's work, and (ii) it's probably better to see what uses for type-changing <- appear in the wild than to preempt them by making them artificially not work.

@axch
Copy link
Collaborator Author

axch commented Nov 7, 2022

By the way, with this change Dex can mimic Haskell's do notation:

foo <- action1 `bind`
bar <- action2 `bind`
baz = pure function
action3

Amusingly, this usage adheres to the convention proposed above: bind doesn't change the return type of the continuation lambda. It changes its input type (i.e., f accepts an a but \x. bind x f accepts an m a), and it changes the return value, but the return type stays m b.

Copy link
Collaborator

@dougalm dougalm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Remarkably small patch. I suspect we'll eventually want to add a version of CBind to UExpr too, so that we can throw type-informed errors during inference (e.g. to ensure that the CPS function doesn't change the result type) but let's see how this feature gets used in practice first.

@axch axch merged commit e73c32b into google-research:main Nov 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add var syntax for convenient access to the state effect
2 participants