google-research / dex-lang

Research language for array processing in the Haskell/ML family
BSD 3-Clause "New" or "Revised" License
1.58k stars 107 forks source link

Add syntax for "the previous value" #1144

Open axch opened 1 year ago

axch commented 1 year ago

With @dougalm.

A use-case is when binding a large expression to a name, e.g.

x = case stuff of
  A -> ...
  B -> ...
  C -> ...
  ...
<x only enters scope down here>

Perhaps it would be nicer to write

case stuff of
  A -> ...
  B -> ...
  C -> ...
  ...
x =^

where =^ is a new lexeme meaning "bind to the previous value in the block". There is also precedent in other languages, especially at a REPL, for a magic identifier that means "the previous value".

Reactions? Discuss!

dougalm commented 1 year ago

I say let's do it!

apaszke commented 1 year ago

Agreed, we've talked about it a few times already!

axch commented 1 year ago

If we're looking to take a leaf from the Common Lisp book, that family of REPLs tends to have a feature that lets you access the kth value back. Are we interested in that, or should we just stick to previous?

Also, this proposal is for a special binder. What do we think about a special expression instead?

x = 2 * ^ + 1

or

x = 2 * it + 1

where ^ or it means "the previous value computed in this block". Pleasant generality or too confusing?

apaszke commented 1 year ago

I find it the special expression quite confusing. Plus ^ is potentially useful for exponentiation, so better not to take it up IMO

dougalm commented 1 year ago

Pleasant generality or too confusing?

I was wondering about this too. On the one hand, I could see it being especially useful in a repl setting where you've just evaluated something and you want to do something with the result but you don't want to have to come up with a name for it. But I agree with Adam that the cost isn't worth it. Any syntax of this flavor breaks usually-semantics-preserving transformations, like inserting a pure decl above the line containing ^. But at least with =^ there's not much else going on on that line, so it stands out as a line to be careful with. If we went the it-as-expression route, then it could be buried deep within an expression (including a multi-line one) and it might not be so obvious.

dougalm commented 1 year ago

Here's an implementation plan: we make a new construct at the grouping level, say CDecl = .... | CPrevValue Group, and we desugar CExpr followed by CPrevValue to ULet in AbstractSyntax.hs. At this desugaring stage we throw a syntax error if the decl preceding the CPrevValue is anything other than CExpr.