-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: pipe operator and placeholder expression (#3987)
Alternative to #3968 that places no restrictions on rhs of pipe, including repeated uses of placeholder '_'. We just define ``` exp_nullary := ... | `_` // placeholder reference exp_bin := ... | <exp_bin> `|>` <exp_bin> // pipe (bind the placeholder) ``` ( `|>` has almost lowest precedence, just above `:`, and associates to the left). and define sugar: ``` '_' ::= _underscore_ <e1> |> <e2> ::= do { let _underscore_ = <e1>; <e2> } ``` (here _underscore_ is some inexpressible identifier - literally '_' in the implementation) pros: - more flexible: can pipe in to anything, not just arguments of function calls - simpler grammar - more natural in a language without linear typing cons: - no rejection of dubious, non-linear: `text.chars() |> Iter.zip(_, _)`; - our recursive `let`s means `_` is also available in `e1`, which is odd, but consistent, and rarely typechecks. Additional examples, not possible in linear #3986 ``` > import I = "mo:base/Iter"; let I : module {...} > import L = "mo:base/List"; let L : module {...} > "hello".chars() |> I.toList _ |> L.zip (_, _) |> { size = L.size _ }; {size = 5} : {size : Nat} ``` Note non-linear piping into (safe) `List.zip`; terminal piping into non-application (a record). TODO: [ ] bespoke error message for use of unbound (_underscore_) (reference not enclosed by a pipe).
- Loading branch information
Showing
24 changed files
with
412 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import Iter "mo:base/Iter"; | ||
import List "mo:base/List"; | ||
|
||
Iter.range(0, 10) |> | ||
Iter.toList _ |> | ||
List.filter<Nat>(_, func n { n % 3 == 0 }) |> | ||
{ multiples = _ }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import Iter "mo:base/Iter"; | ||
import List "mo:base/List"; | ||
|
||
{ multiples = | ||
List.filter<Nat>( | ||
Iter.toList(Iter.range(0, 10)), | ||
func n { n % 3 == 0 }) }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Piping values into expressions | ||
|
||
It can sometimes be hard to read deeply nested expressions involving several function applications. | ||
|
||
``` motoko file=./examples/Unpiped.mo#L1-L8 | ||
``` | ||
|
||
This expression take the range of numbers `0`..`10`, converts it to a list, filters the list for multiples of three and returns a record containing the result. | ||
|
||
To make such expressions more readable, you can use Motoko's pipe operator `<exp1> |> <exp2>`. | ||
The operator evaluates the first argument `<exp1>`, and lets you refer to its value in `<exp2>` using the special placeholder expression `_`. | ||
|
||
Using this, you can write the former expression as: | ||
|
||
``` motoko file=./examples/Piped.mo#L1-L8 | ||
``` | ||
|
||
Now, the textual order of operations corresponds to our English explanation above: "this expression takes the range of numbers `0`..`10`, converts it to a list, filters the list for multiples of three and returns a record containing the result". | ||
|
||
|
||
The pipe expression `<exp1> |> <exp2>` is just syntactic sugar for the following block binding `<exp1>` to a reserved | ||
placeholder identifier, `p`, before returning `<exp2>`: | ||
|
||
``` bnf | ||
do { let p = <exp1>; <exp2> } | ||
``` | ||
|
||
The otherwise inaccessible placeholder identifier `p` can only referenced by the placeholder expression `_`. | ||
Multiple references to `_` are allowed and refer to the same value within the same pipe operation. | ||
|
||
|
||
Note that using `_` as an expression outside of a pipe operation, where it is undefined, is an error. | ||
|
||
For example: | ||
|
||
``` motoko | ||
let x = _; | ||
``` | ||
|
||
produces the compile-time error "type error [M0057], unbound variable _". | ||
|
||
(Internally, the compiler uses the reserved identifier `_` as the name for the placeholder called `p` above, so this `let` is just referencing an undefined variable). | ||
|
||
|
||
See [here](language-manual.md#pipe-operators-and-placeholder-expressions) for more details. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
pipe-ill-typed.mo:7.33-7.34: type error [M0096], expression of type | ||
{#B} | ||
cannot produce expected type | ||
{#A} | ||
pipe-ill-typed.mo:11.37-11.38: type error [M0096], expression of type | ||
{#A} | ||
cannot produce expected type | ||
{#B} | ||
pipe-ill-typed.mo:16.33-16.34: type error [M0096], expression of type | ||
{#A} | ||
cannot produce expected type | ||
(A__9, B) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Return code 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
type A = {#A}; | ||
type B = {#B}; | ||
|
||
func f2<T1, T2>(x1 : T1, x2 : T2) : (T1, T2) { (x1, x2) }; | ||
|
||
do { | ||
let (#A, #B) = #B |> f2<A, B>(_, #B); // type error | ||
}; | ||
|
||
do { | ||
let (#A, #B) = #A |> f2<A, B>(#A, _); // type error | ||
}; | ||
|
||
|
||
do { | ||
let (#A, #B) = #A |> f2<A, B> _; // type error | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
1: | ||
#A | ||
f | ||
#B | ||
2: | ||
#B | ||
f | ||
#A | ||
3: | ||
#A | ||
f | ||
#B | ||
#C | ||
4: | ||
#B | ||
f | ||
#A | ||
#C | ||
5: | ||
#C | ||
f | ||
#A | ||
#B |
Oops, something went wrong.