From e46bda6e0b9771c524752b673a4e3012c23f75bb Mon Sep 17 00:00:00 2001 From: ecdeuts Date: Tue, 5 May 2020 15:15:42 -0400 Subject: [PATCH 01/12] completed first draft of labeled product types section --- 1-labeled-tuples/1-labeled-tuples.md | 217 +++++++++++++++------------ 1 file changed, 121 insertions(+), 96 deletions(-) diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index f71a404..0ab9af6 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -1,96 +1,121 @@ -# Introduction - -TODO: what are labeled products -Labeled products are a value similar to products, but some/all elements have a label. This label can be used then for projection, so elements within the product can be accessed either positionally or by the label. -TODO: why do we want them in Hazel -Adding labeled products helps make the tuples become more robust, so more complex products can be easily used. Accesing a longer tuple using only positional arguments adds unneccsary bulk to the code. Having labels allows for easy projection. The labeled products can also serve a similar use as records in other languages. -TODO: what do we have now -Currently only unlabeled tuples are supported in Hazel, and elements can only be accessed positionally using let statements or case statements. -# Labeled Product Types - -TODO: add `.label` as a new type form -τ -TODO: recognize operator sequences containing `.label1 ty1, .label ty2, ..., .labeln tyn` as labeled product types -TODO: do we want to allow partially labeled product types? - - allow non-labled prefix, but once you use a label as subsequent positions have to be labeled - - alternatively, allow labeled and non-labeled positions to be interleaved - TODO: how does this affect type equivalence? e.g. are `(.x Num, .y Num, .z Num) == (.z Num, .y Num, .x Num)` - TODO: singleton labeled products -- should we support them (`.x Num` is a labeled product type?) - TODO: syntax errors - * `.label1 .label2 ty` - * `.label1` by itself - * `.label1 ty .label2` - * we will need some way to mark erroneous uses of labels and indicate that in the cursor inspector - * duplicate labels: `(.label1 Num, .label1 Num)` is not a valid type, so we also need duplicate label errors - - does the error message go on the subsequent uses, or on the type as a whole? - -# Labeled Tuple Expressions -TODO: add `.label` as a new expression form -TODO: similar considerations as above -TODO: can you omit labels by providing values in order: `(1, 2, 3) <= (.x Num, .y Num, .z Num)` -TODO: "Record punning" in Reason: `{x, y, z} => {x: x, y: y, z: z}` -- is there anything analogous that we can do? Does this interact with positional values? `(y, x, z) <= (.x Num, .y Num, .z Num)` does that operate positionally or via punning? -TODO: partially labeled values, where some of the arguments are in order: `(1, 2, .z 3) <= (.x Num, .y Num, .z Num)`. what about interleaving vs. requiring all the explicit labels at the end ala Python? -TODO: what are the type synthesis and type analysis rules for the labeled tuple expressions - -# Projection Expressions -TODO: add `e.label` as a new expression form -TODO: can you press backspace on `e |.label` and get to `e.label`? -TODO: can you press space on `e|.label` and get to `e .label` -TODO: what are the type synthesis and type analysis rules? - -# Labeled Tuple Patterns -TODO: similar considerations to labeled tuple expressions -TODO: we might want punning for labeled tuple patterns: -```let f = fun(.x, .y) ... -f(.x 1, .y 2)``` -instead of -```let f = fun(.x x, .y y) ... -f(.x 1, .y 2)``` -TODO: what are the pattern type synthesis and pattern type analysis rules? (ask Yongwei for paper draft if you want to formalize) - -# Other Ideas - -TODO: clean up - -# Overall Possibilities - -Option 1: Use reason like ~label annotations -Option 2: Use a space to separate between label and type/expression/pattern. Period operator is added before label to specify that it is a label. Ties in well with linking the period to labeled products, as the period is also used for projection. Possible problem: Issues with using a period as both binary operator (projection) and unary operator (label definition) -Option 3: Use space operator between labels and type/expression/pattern. Problem: No way to tell distinction between undefined function variable application and labeled expression -Option 4: Use colon operator between labels and type/expression/pattern. Problem: Confusion between type annotations and labeled pair type annotation -Option 5: Use colons and braces to signify a labeled tuple. Problem: This syntax is more typical for a record, and may create confusion about labeled tuples as a value and records as a type definition, as well as create issues if there are any future plans for adding records to Hazel, makes development task larger to define braces syntax - -# Labeled Product Types - -Currently: `ty1, ty2, ..., tyn` -With Labels: `~label1: ty1, ~label2: ty2,..., ~labeln: tyn` -With labels: `.label1 ty1, .label2 ty2, ..., .labeln tyn` -With labels: `label1 ty1, label2 ty2, ..., labeln tyn` -With Labels: `label1: ty1, label2: ty2, ..., labeln: tyn` -With labels: `{label1: ty1, label2:ty2, ..., labeln:tyn}' - -# Labeled Product Expressions - -Currently: `e1, e2, ..., en` -With labels: `~label1=ty1, ~label2=ty2, ..., ~labeln=tyn` -With Labels: `.label1 e1, .label2 e2, ..., .labeln en` -With Labels: `label1 e1, label2: e2, ..., labeln: en` -With Labels: `label1: e1, label2: e2, ..., labeln: en` -With labels: `{label1: e1, label2:e2, ..., labeln:e2}' - -# Labeled Product Patterns -Currently: `p1, p2, ..., pn` -With Labels: `~label=ty1, ~label=ty2,..., ~labeln=tyn` -With Labels: `.label1 p1, .label2 p2, ..., .labeln pn` -With Labels: `label1 p1, label2 p2, ..., labeln pn` -With Labels: `label1: p1, label2: p2, ..., labeln: pn` -With labels: `{label1: p1, label2: p2, ..., labeln: pn}' - -In pattern position, we would also want to support type annotations. - -# Projection - -Currently: no projection -With Labels: `e.label` - -(For many of these, we will need label holes.) +# Introduction + + +Labeled products are a value similar to products, but some/all elements have a label. This label can be used then for projection, so elements within the product can be accessed either positionally or by the label. + +Adding labeled products helps make the tuples become more robust, so more complex products can be easily used. Accesing a longer tuple using only positional arguments adds unneccsary bulk to the code. Having labels allows for easy projection. The labeled products can also serve a similar use as records in other languages. + +Currently only unlabeled tuples are supported in Hazel, and elements can only be accessed positionally using let statements or case statements. +# Labeled Product Types + +TODO: add `.label` as a new type form
+ +τ ::= ...
+| .label
+| .label1 τ1, .label2 τ2 ... , .labeln τn
+ + +Partially labeled product types are allowed, and labels and non-labeled positions can be interleaved. +For example, the labeled product type `(.x Num, Num, .y Num)` is allowed. + +Bcause a labeld product may still be used with a positional arguments with partially labeld types, the type equivalence considers the order of the labels with equlivalence. For example, `(.x Num, .y Num, .z Num) != (.z Num, .y Num, .x Num)` because the order of the labels is different. + +Singleton label products are supported. For example, `.x Num` is supported. + +## Type Syntax Errors + +A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error.
+(Question: Would this produce an error given that singleton products are supported?) + +A label cannot exist by itself, it is given meaning by having a type follow it. For example, `.label1 ` by itself produces an error.
+Proposed Error Message: Error Curosr appears on `.label1`
+Expecting a type of Labeled Product / Got Inconsitent type of Label + +Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 ty .label2` produces an error.
+Proposed Error Message: Error cursor appears on `.label2`
+Expecting a type of Labeled Product / Got Inconsitent type of Label + +Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the type `.label1 Num, .label1 Num, .label2 Num, .label1 Bool` will have erros on the second use of `.label1 Num` and `.label1 Bool` + + + +# Labeled Tuple Expressions +TODO: add `.label` as a new expression form +TODO: similar considerations as above +TODO: can you omit labels by providing values in order: `(1, 2, 3) <= (.x Num, .y Num, .z Num)` +TODO: "Record punning" in Reason: `{x, y, z} => {x: x, y: y, z: z}` -- is there anything analogous that we can do? Does this interact with positional values? `(y, x, z) <= (.x Num, .y Num, .z Num)` does that operate positionally or via punning? +TODO: partially labeled values, where some of the arguments are in order: `(1, 2, .z 3) <= (.x Num, .y Num, .z Num)`. what about interleaving vs. requiring all the explicit labels at the end ala Python? +TODO: what are the type synthesis and type analysis rules for the labeled tuple expressions + +# Projection Expressions +TODO: add `e.label` as a new expression form +TODO: can you press backspace on `e |.label` and get to `e.label`? +TODO: can you press space on `e|.label` and get to `e .label` +TODO: what are the type synthesis and type analysis rules? + +# Labeled Tuple Patterns +TODO: similar considerations to labeled tuple expressions +TODO: we might want punning for labeled tuple patterns: +```let f = fun(.x, .y) ... +f(.x 1, .y 2)``` +instead of +```let f = fun(.x x, .y y) ... +f(.x 1, .y 2)``` +TODO: what are the pattern type synthesis and pattern type analysis rules? (ask Yongwei for paper draft if you want to formalize) + +# Other Ideas + +TODO: clean up + +# Overall Possibilities + +Option 1: Use reason like ~label annotations +Option 2: Use a space to separate between label and type/expression/pattern. Period operator is added before label to specify that it is a label. Ties in well with linking the period to labeled products, as the period is also used for projection. Possible problem: Issues with using a period as both binary operator (projection) and unary operator (label definition) +Option 3: Use space operator between labels and type/expression/pattern. Problem: No way to tell distinction between undefined function variable application and labeled expression +Option 4: Use colon operator between labels and type/expression/pattern. Problem: Confusion between type annotations and labeled pair type annotation +Option 5: Use colons and braces to signify a labeled tuple. Problem: This syntax is more typical for a record, and may create confusion about labeled tuples as a value and records as a type definition, as well as create issues if there are any future plans for adding records to Hazel, makes development task larger to define braces syntax + +# Labeled Product Types + +Currently: `ty1, ty2, ..., tyn` +With Labels: `~label1: ty1, ~label2: ty2,..., ~labeln: tyn` +With labels: `.label1 ty1, .label2 ty2, ..., .labeln tyn` +With labels: `label1 ty1, label2 ty2, ..., labeln tyn` +With Labels: `label1: ty1, label2: ty2, ..., labeln: tyn` +With labels: `{label1: ty1, label2:ty2, ..., labeln:tyn}' + +# Labeled Product Expressions + +Currently: `e1, e2, ..., en` +With labels: `~label1=ty1, ~label2=ty2, ..., ~labeln=tyn` +With Labels: `.label1 e1, .label2 e2, ..., .labeln en` +With Labels: `label1 e1, label2: e2, ..., labeln: en` +With Labels: `label1: e1, label2: e2, ..., labeln: en` +With labels: `{label1: e1, label2:e2, ..., labeln:e2}' + +# Labeled Product Patterns +Currently: `p1, p2, ..., pn` +With Labels: `~label=ty1, ~label=ty2,..., ~labeln=tyn` +With Labels: `.label1 p1, .label2 p2, ..., .labeln pn` +With Labels: `label1 p1, label2 p2, ..., labeln pn` +With Labels: `label1: p1, label2: p2, ..., labeln: pn` +With labels: `{label1: p1, label2: p2, ..., labeln: pn}' + +In pattern position, we would also want to support type annotations. + +# Projection + +Currently: no projection +With Labels: `e.label` + +(For many of these, we will need label holes.) From d7abc186ef8d0dbe81227a58912d770d157ec6c3 Mon Sep 17 00:00:00 2001 From: ecdeuts Date: Tue, 5 May 2020 15:18:47 -0400 Subject: [PATCH 02/12] Update 1-labeled-tuples.md --- 1-labeled-tuples/1-labeled-tuples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index 0ab9af6..5a1dfc6 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -22,7 +22,7 @@ Bcause a labeld product may still be used with a positional arguments with parti Singleton label products are supported. For example, `.x Num` is supported. -## Type Syntax Errors +### Type Syntax Errors A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error.
(Question: Would this produce an error given that singleton products are supported?) From 7aeb30a1cf95595161e6e03827bc49dbf4fc3c78 Mon Sep 17 00:00:00 2001 From: ecdeuts Date: Tue, 5 May 2020 15:58:19 -0400 Subject: [PATCH 03/12] added comments from Cyrus' feedback --- 1-labeled-tuples/1-labeled-tuples.md | 20 +++++++++++++------- README.md | 8 ++++---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index 5a1dfc6..fa45602 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -9,10 +9,14 @@ Currently only unlabeled tuples are supported in Hazel, and elements can only be # Labeled Product Types TODO: add `.label` as a new type form
- -τ ::= ...
+TODO: List the files you expect ot edit for each thing, and a sentance about what you expect to do + + + +```τ ::= ...
| .label
-| .label1 τ1, .label2 τ2 ... , .labeln τn
+| .label1 τ1, .label2 τ2 ... , .labeln τn
``` + Partially labeled product types are allowed, and labels and non-labeled positions can be interleaved. @@ -22,20 +26,22 @@ Bcause a labeld product may still be used with a positional arguments with parti Singleton label products are supported. For example, `.x Num` is supported. + +# What about records? ### Type Syntax Errors A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error.
-(Question: Would this produce an error given that singleton products are supported?) A label cannot exist by itself, it is given meaning by having a type follow it. For example, `.label1 ` by itself produces an error.
Proposed Error Message: Error Curosr appears on `.label1`
-Expecting a type of Labeled Product / Got Inconsitent type of Label +Expecting Expecting a Type Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 ty .label2` produces an error.
Proposed Error Message: Error cursor appears on `.label2`
-Expecting a type of Labeled Product / Got Inconsitent type of Label +Expecting a type Got a label -Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the type `.label1 Num, .label1 Num, .label2 Num, .label1 Bool` will have erros on the second use of `.label1 Num` and `.label1 Bool` +Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the type `.label1 Num, .label1 Num, .label2 Num, .label1 Bool` will have errors on the second use of `.label1 Num` and `.label1 Bool` +Error Message + -```τ ::= ...
-| .label
-| .label1 τ1, .label2 τ2 ... , .labeln τn
``` +Edited File: UHTyp.re +To add labeled product types, the operator and opearnd types will need to be expanded like so: +``` +type operator = + | Arrow + | Prod + | Sum + | Space; +``` +Space will be left associateive and have the highest precedence. +``` +type operand = + | Hole + | Unit + | Int + | Float + | Bool + | Parenthesized(t) + | List(t) + | Label; +``` Partially labeled product types are allowed, and labels and non-labeled positions can be interleaved. For example, the labeled product type `(.x Num, Num, .y Num)` is allowed. -Bcause a labeld product may still be used with a positional arguments with partially labeld types, the type equivalence considers the order of the labels with equlivalence. For example, `(.x Num, .y Num, .z Num) != (.z Num, .y Num, .x Num)` because the order of the labels is different. - Singleton label products are supported. For example, `.x Num` is supported. +### Type Equivalence + +Bcause a labeld product may still be used with a positional arguments with partially labeld types, the type equivalence considers the order of the labels with equlivalence. For example, `(.x Num, .y Num, .z Num) != (.z Num, .y Num, .x Num)` because the order of the labels is different. + -# What about records? ### Type Syntax Errors A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error.
@@ -56,19 +75,88 @@ Error Message - does the error message go on the subsequent uses, or on the type as a whole? --> # Labeled Tuple Expressions -TODO: add `.label` as a new expression form -TODO: similar considerations as above -TODO: can you omit labels by providing values in order: `(1, 2, 3) <= (.x Num, .y Num, .z Num)` + +Edited File: UHExp.re +To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels. +``` +type operator = + | Space + | Plus + | Minus + | Times + | FPlus + | FMinus + | FTimes + | LessThan + | GreaterThan + | Equals + | Comma + | Cons + | And + | Or + | Dot; +``` +The Dot operator will be left associative and have highest precedence. +``` +operand = + | EmptyHole(MetaVar.t) + | Var(ErrStatus.t, VarErrStatus.t, Var.t) + | IntLit(ErrStatus.t, string) + | FloatLit(ErrStatus.t, string) + | BoolLit(ErrStatus.t, bool) + | ListNil(ErrStatus.t) + | Lam(ErrStatus.t, UHPat.t, option(UHTyp.t), t) + | Inj(ErrStatus.t, InjSide.t, t) + | Case(ErrStatus.t, t, rules, option(UHTyp.t)) + | Parenthesized(t) + | ApPalette(ErrStatus.t, PaletteName.t, SerializedModel.t, splice_info) + | Label(t) + ``` + + +Partially labeled product expressions are allowed, and labels and non-labeled positions can be interleaved. +For example, the labeled product type `(.x 2, 3, .y True)` is allowed. + +Singleton label products are supported. For example, `.x 2` is supported. + + +An unlabeld product expression can analyze to a labeled product expression, allowing you to ommit labels. For example, `(1, 2, 3) <= (.x Num, .y Num, .z Num)` is valid and each value in `(1,2,3)`. This operation happens positionally, and does not assign labels based on variable name if variables are used. For example, `(y, x, z) <= (.x Num, .y Num, .z Num)` is valid. + + +### Punning +Languages such as reason have record punning where a record's labels can be implied when it is declared using variables. For example, `{x, y, z} => {x: x, y: y, z: z}` is valid. This is a possible function of labeled tupeles in Hazel. An example of this would be if `(x, y, z) => (x: x, y: y, z: z)`. However, this creates a question of if every tuple created with variables should be a labeled tuple. Given this additional complexity and added development costs, I believe that labeled tuple punning should be considered out of scope for the inital addition of labeled tuples. -# Projection Expressions +### Projection Expressions +Labels can be used to access elements of a pair through projection expressions. TODO: add `e.label` as a new expression form -TODO: can you press backspace on `e |.label` and get to `e.label`? -TODO: can you press space on `e|.label` and get to `e .label` +`e.label` will be the new expression form. It will use the dot operator as shown above. `e.label` expects `e` to be a labeled tuple type and `label` to match one of the labels within `e`. `e.label` will retun the value that has the label `label`. +#### Backspace +You press backspace on `e |.label` and get to `e.label` + +You press space on `e|.label` and get to `e .label` + +### Type Sythesis and Type Analysis Rules TODO: what are the type synthesis and type analysis rules? + +### Expression Syntax Errors + +A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 e` produces an error.
+ +A label cannot exist by itself, it is given meaning by having an expression follow it. For example, `.label1 ` by itself produces an error.
+Proposed Error Message: Error Curosr appears on `.label1`
+Expecting a Type Got a Label + +Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 e1 .label2` produces an error.
+Proposed Error Message: Error cursor appears on `.label2`
+Expecting an expression Got a label + +Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the expression `.label1 1, .label1 3, .label2 4, .label1 True` will have errors on `.label1 3` and `.label1 True` +Error Message + # Labeled Tuple Patterns TODO: similar considerations to labeled tuple expressions TODO: we might want punning for labeled tuple patterns: @@ -79,7 +167,9 @@ instead of f(.x 1, .y 2)``` TODO: what are the pattern type synthesis and pattern type analysis rules? (ask Yongwei for paper draft if you want to formalize) -# Other Ideas +# What about records? + +# Appendix: Other Ideas TODO: clean up From b3825df75d0c2c68d81f17802f71eac36503aab0 Mon Sep 17 00:00:00 2001 From: ecdeuts Date: Mon, 11 May 2020 16:12:22 -0400 Subject: [PATCH 05/12] labeled tuples pattern section draft done and records section draft done --- 1-labeled-tuples/1-labeled-tuples.md | 74 +++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index 40a8e44..c564658 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -144,7 +144,7 @@ TODO: what are the type synthesis and type analysis rules? ### Expression Syntax Errors -A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 e` produces an error.
+A label must be followed by a valid expression and comma operator, not another label. For example, `.label1 .label2 e` produces an error.
A label cannot exist by itself, it is given meaning by having an expression follow it. For example, `.label1 ` by itself produces an error.
Proposed Error Message: Error Curosr appears on `.label1`
@@ -158,22 +158,70 @@ Duplicate labels within a tuple are not valid, so they produce an error. The er Error Message # Labeled Tuple Patterns -TODO: similar considerations to labeled tuple expressions -TODO: we might want punning for labeled tuple patterns: -```let f = fun(.x, .y) ... -f(.x 1, .y 2)``` -instead of -```let f = fun(.x x, .y y) ... -f(.x 1, .y 2)``` -TODO: what are the pattern type synthesis and pattern type analysis rules? (ask Yongwei for paper draft if you want to formalize) +Edited Files: UHPat.re +To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels. +``` +type operator = + | Comma + | Space + | Dot; +``` +The Dot operator will be left associative and have highest precedence. +``` +and operand = + | EmptyHole(MetaVar.t) + | Wild(ErrStatus.t) + | Var(ErrStatus.t, VarErrStatus.t, Var.t) + | IntLit(ErrStatus.t, string) + | FloatLit(ErrStatus.t, string) + | BoolLit(ErrStatus.t, bool) + | ListNil(ErrStatus.t) + | Parenthesized(t) + | Inj(ErrStatus.t, InjSide.t, t); + | Label(ErrStatus.t, string) +``` + +Partially labeled product patterns are allowed, and labels and non-labeled positions can be interleaved. +For example, the labeled product type `(.x pat1, pat2, .y pat3)` is allowed. -# What about records? +Singleton label products are supported. For example, `.x pat1` is supported. -# Appendix: Other Ideas +### Sythesis and Analysis + +An unlabeld product pattern can match to a labeled product expression, allowing you to ommit labels. For example, `(.x 1, .y 2, .z 3)` can match on the pattern `(a, b, c)`. This operation happens positionally. + +A labeled tuple pattern must match the label names and the order of a labeled tuple expression for a pattern match. For example, `(.x a, .y b, .z c)` will match with `(.x 1, .y 2, .z 3)` but will not match with `(.y 1, .z 2, .x 3)` because the order does not match. + +### Punning +Punning may be useful for labeled tuple patterns, where the label can be used to access the element rather than adding an aditional variable. For example, with punning this code snippit: +``` +let f = fun(.x, .y) +f(.x 1, .y 2) +``` +would be equivalent to +``` +let f = fun(.x x, .y y) +f(.x 1, .y 2) +``` -TODO: clean up +This would be a great quality of life improvement to patterns with labeled tuples, and will be attempeted with the initial impelemntation of labeled tuples. It will be considered lower priority, since it is not required for labeled tuples patterns. -# Overall Possibilities +### Pattern Syntax Errors + +Multiple label must be followed by the comma operator, not another label. For example, `.label1 .label2` produces an error.
+ +Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 p1 .label2 p2` produces an error.
+Proposed Error Message: Error cursor appears on `.label2`
+Expecting an pattern Got a label + +Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, the expression `.label1 p1, .label1 p2, .label2 p3, .label1 p4` will have errors on `.label1 p2` and `.label1 p4` +Error Message + +# What about records? +Records in other languages are very similar to the labeled tuples in this propoasal. Records are typically a data structure that bundles data together with labels and values, and the values are accessed using projection with the labels. The values are unordered in a record, while the values are ordered in a labeled tuple. A labeled tuple is able to perform the same functions as a record, while adding additional functionality by ordering data. If labeled tuples are sucessfully added to Hazel, then records will be redundant in Hazel. + +# Appendix: Other Ideas +While creating this proposal, I considered many other ideas for Hazel labels. These ideas are detailed below. Option 1: Use reason like ~label annotations Option 2: Use a space to separate between label and type/expression/pattern. Period operator is added before label to specify that it is a label. Ties in well with linking the period to labeled products, as the period is also used for projection. Possible problem: Issues with using a period as both binary operator (projection) and unary operator (label definition) From ebe5c5caa110099ab0a23bf97bea415b6953b83d Mon Sep 17 00:00:00 2001 From: ecdeuts Date: Tue, 12 May 2020 14:38:15 -0400 Subject: [PATCH 06/12] added synthesis and analysis rule images for labled tuple expressions --- 1-labeled-tuples/1-labeled-tuples.md | 220 ++++++++++++++------------- 1-labeled-tuples/ana_1.png | Bin 0 -> 3858 bytes 1-labeled-tuples/ana_2.png | Bin 0 -> 4043 bytes 1-labeled-tuples/syn_1.png | Bin 0 -> 6029 bytes 1-labeled-tuples/syn_2.png | Bin 0 -> 5312 bytes 5 files changed, 114 insertions(+), 106 deletions(-) create mode 100644 1-labeled-tuples/ana_1.png create mode 100644 1-labeled-tuples/ana_2.png create mode 100644 1-labeled-tuples/syn_1.png create mode 100644 1-labeled-tuples/syn_2.png diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index c564658..ca38fda 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -1,160 +1,168 @@ # Introduction -Labeled products are a value similar to products, but some/all elements have a label. This label can be used then for projection, so elements within the product can be accessed either positionally or by the label. +Labeled products are a value similar to products, but some/all elements have a label. This label can be used then for projection. This allows elements within the product can be accessed either positionally or by the label. -Adding labeled products helps make the tuples become more robust, so more complex products can be easily used. Accesing a longer tuple using only positional arguments adds unneccsary bulk to the code. Having labels allows for easy projection. The labeled products can also serve a similar use as records in other languages. +Adding labeled products helps make the tuples become more robust, so more complex products can be easily used. Accesing a longer tuple using only positional arguments adds unneccsary bulk to the code. Having labels allows for easy access of values in a product. The labeled products can also serve a similar use as records in other languages. Currently only unlabeled tuples are supported in Hazel, and elements can only be accessed positionally using let statements or case statements. # Labeled Product Types - +Files to Edit: UHTyp.re -Edited File: UHTyp.re + To add labeled product types, the operator and opearnd types will need to be expanded like so: ``` type operator = - | Arrow - | Prod - | Sum - | Space; + | Arrow + | Prod + | Sum + | Space; ``` Space will be left associateive and have the highest precedence. ``` type operand = - | Hole - | Unit - | Int - | Float - | Bool - | Parenthesized(t) - | List(t) - | Label; + | Hole + | Unit + | Int + | Float + | Bool + | Parenthesized(t) + | List(t) + | Label; ``` Partially labeled product types are allowed, and labels and non-labeled positions can be interleaved. -For example, the labeled product type `(.x Num, Num, .y Num)` is allowed. +For example, the labeled product type `(.x Num, Num, .y Num)` is allowed. -Singleton label products are supported. For example, `.x Num` is supported. +Singleton label products are supported. For example, `.x Num` is supported. ### Type Equivalence -Bcause a labeld product may still be used with a positional arguments with partially labeld types, the type equivalence considers the order of the labels with equlivalence. For example, `(.x Num, .y Num, .z Num) != (.z Num, .y Num, .x Num)` because the order of the labels is different. +Bcause a labeld product may still be used with a positional arguments with partially labeld types, the type equivalence considers the order of the labels with equlivalence. For example, `(.x Num, .y Num, .z Num) != (.z Num, .y Num, .x Num)` because the order of the labels is different. ### Type Syntax Errors -A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error.
+A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error.
+Proposed Error Message: Error Curosr appears on `.label1`
+Expecting a Type Got a Label -A label cannot exist by itself, it is given meaning by having a type follow it. For example, `.label1 ` by itself produces an error.
+A label cannot exist by itself, it is given meaning by having a type follow it. For example, `.label1 ` by itself produces an error.
Proposed Error Message: Error Curosr appears on `.label1`
-Expecting Expecting a Type +Expecting a Type Got a Label -Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 ty .label2` produces an error.
+Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 ty .label2` produces an error.
Proposed Error Message: Error cursor appears on `.label2`
Expecting a type Got a label -Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the type `.label1 Num, .label1 Num, .label2 Num, .label1 Bool` will have errors on the second use of `.label1 Num` and `.label1 Bool` -Error Message +Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the type `.label1 Num, .label1 Num, .label2 Num, .label1 Bool` will have errors on the second use of `.label1 Num` and `.label1 Bool` +Proposed Error Message: Error Curosr appears on second use of `.label1 Num` and `.label1 Bool`
+Expecting a Unique Label Got a Duplicate Label + - + - does the error message go on the subsequent uses, or on the type as a whole? --> # Labeled Tuple Expressions -Edited File: UHExp.re +Files to Edit: UHExp.re + To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels. ``` type operator = - | Space - | Plus - | Minus - | Times - | FPlus - | FMinus - | FTimes - | LessThan - | GreaterThan - | Equals - | Comma - | Cons - | And - | Or - | Dot; + | Space + | Plus + | Minus + | Times + | FPlus + | FMinus + | FTimes + | LessThan + | GreaterThan + | Equals + | Comma + | Cons + | And + | Or + | Dot; ``` The Dot operator will be left associative and have highest precedence. ``` operand = - | EmptyHole(MetaVar.t) - | Var(ErrStatus.t, VarErrStatus.t, Var.t) - | IntLit(ErrStatus.t, string) - | FloatLit(ErrStatus.t, string) - | BoolLit(ErrStatus.t, bool) - | ListNil(ErrStatus.t) - | Lam(ErrStatus.t, UHPat.t, option(UHTyp.t), t) - | Inj(ErrStatus.t, InjSide.t, t) - | Case(ErrStatus.t, t, rules, option(UHTyp.t)) - | Parenthesized(t) - | ApPalette(ErrStatus.t, PaletteName.t, SerializedModel.t, splice_info) - | Label(t) - ``` + | EmptyHole(MetaVar.t) + | Var(ErrStatus.t, VarErrStatus.t, Var.t) + | IntLit(ErrStatus.t, string) + | FloatLit(ErrStatus.t, string) + | BoolLit(ErrStatus.t, bool) + | ListNil(ErrStatus.t) + | Lam(ErrStatus.t, UHPat.t, option(UHTyp.t), t) + | Inj(ErrStatus.t, InjSide.t, t) + | Case(ErrStatus.t, t, rules, option(UHTyp.t)) + | Parenthesized(t) + | ApPalette(ErrStatus.t, PaletteName.t, SerializedModel.t, splice_info) + | Label(t) + ``` Partially labeled product expressions are allowed, and labels and non-labeled positions can be interleaved. -For example, the labeled product type `(.x 2, 3, .y True)` is allowed. +For example, the labeled product expression `(.x 2, 3, .y True)` is allowed. -Singleton label products are supported. For example, `.x 2` is supported. +Singleton label product expressions are supported. For example, `.x 2` is supported. -An unlabeld product expression can analyze to a labeled product expression, allowing you to ommit labels. For example, `(1, 2, 3) <= (.x Num, .y Num, .z Num)` is valid and each value in `(1,2,3)`. This operation happens positionally, and does not assign labels based on variable name if variables are used. For example, `(y, x, z) <= (.x Num, .y Num, .z Num)` is valid. +An unlabeld product expression can analyze to a labeled product expression, allowing you to omit labels. For example, `(1, 2, 3) <= (.x Num, .y Num, .z Num)` is valid and each value in `(1,2,3)`. This operation happens positionally, and does not assign labels based on variable name if variables are used. For example, `(y, x, z) <= (.x Num, .y Num, .z Num)` is valid. +TODO: what are the type synthesis and type analysis rules for the labeled tuple expressions --> ### Punning -Languages such as reason have record punning where a record's labels can be implied when it is declared using variables. For example, `{x, y, z} => {x: x, y: y, z: z}` is valid. This is a possible function of labeled tupeles in Hazel. An example of this would be if `(x, y, z) => (x: x, y: y, z: z)`. However, this creates a question of if every tuple created with variables should be a labeled tuple. Given this additional complexity and added development costs, I believe that labeled tuple punning should be considered out of scope for the inital addition of labeled tuples. +Some languages, such as Reason, have record punning. This is where a record's labels can be implied when it is declared using variables. For example, `{x, y, z} => {x: x, y: y, z: z}` is true. Similar punning fuctionality could be implemented in Hazel. For example, if this punnign was implemented `(x, y, z) => (x: x, y: y, z: z)` would hold true. However, this creates a question of if every tuple created with variables should be a labeled tuple. Given this additional complexity and added development costs, I believe that labeled tuple punning should be considered out of scope for the inital addition of labeled tuples. ### Projection Expressions -Labels can be used to access elements of a pair through projection expressions. -TODO: add `e.label` as a new expression form -`e.label` will be the new expression form. It will use the dot operator as shown above. `e.label` expects `e` to be a labeled tuple type and `label` to match one of the labels within `e`. `e.label` will retun the value that has the label `label`. +Labels can be used to access elements of a pair through projection expressions. + +`e.label` will be the new expression form. It will use the dot operator, which was already added to the operator type above. `e.label` expects `e` to be a labeled tuple type and `label` to match one of the labels within `e`. `e.label` will retun the value that has the label `label`. #### Backspace You press backspace on `e |.label` and get to `e.label` You press space on `e|.label` and get to `e .label` -### Type Sythesis and Type Analysis Rules -TODO: what are the type synthesis and type analysis rules? +### Type Sythesis and Type Analysis Rules for Labeled Product Expressions +#### Synthesis +![alt text][Syn Labeled Tuple list.png] +#### Analysis + ### Expression Syntax Errors -A label must be followed by a valid expression and comma operator, not another label. For example, `.label1 .label2 e` produces an error.
+A label must be followed by a valid expression and comma operator, not another label. For example, `.label1 .label2 e` produces an error.
-A label cannot exist by itself, it is given meaning by having an expression follow it. For example, `.label1 ` by itself produces an error.
+A label cannot exist by itself, it is given meaning by having an expression follow it. For example, `.label1 ` by itself produces an error.
Proposed Error Message: Error Curosr appears on `.label1`
Expecting a Type Got a Label -Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 e1 .label2` produces an error.
+Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 e1 .label2` produces an error.
Proposed Error Message: Error cursor appears on `.label2`
Expecting an expression Got a label -Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the expression `.label1 1, .label1 3, .label2 4, .label1 True` will have errors on `.label1 3` and `.label1 True` +Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the expression `.label1 1, .label1 3, .label2 4, .label1 True` will have errors on `.label1 3` and `.label1 True` Error Message # Labeled Tuple Patterns @@ -162,38 +170,38 @@ Edited Files: UHPat.re To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels. ``` type operator = - | Comma - | Space - | Dot; + | Comma + | Space + | Dot; ``` The Dot operator will be left associative and have highest precedence. ``` and operand = - | EmptyHole(MetaVar.t) - | Wild(ErrStatus.t) - | Var(ErrStatus.t, VarErrStatus.t, Var.t) - | IntLit(ErrStatus.t, string) - | FloatLit(ErrStatus.t, string) - | BoolLit(ErrStatus.t, bool) - | ListNil(ErrStatus.t) - | Parenthesized(t) - | Inj(ErrStatus.t, InjSide.t, t); - | Label(ErrStatus.t, string) + | EmptyHole(MetaVar.t) + | Wild(ErrStatus.t) + | Var(ErrStatus.t, VarErrStatus.t, Var.t) + | IntLit(ErrStatus.t, string) + | FloatLit(ErrStatus.t, string) + | BoolLit(ErrStatus.t, bool) + | ListNil(ErrStatus.t) + | Parenthesized(t) + | Inj(ErrStatus.t, InjSide.t, t); + | Label(ErrStatus.t, string) ``` Partially labeled product patterns are allowed, and labels and non-labeled positions can be interleaved. -For example, the labeled product type `(.x pat1, pat2, .y pat3)` is allowed. +For example, the labeled product type `(.x pat1, pat2, .y pat3)` is allowed. -Singleton label products are supported. For example, `.x pat1` is supported. +Singleton label products are supported. For example, `.x pat1` is supported. ### Sythesis and Analysis -An unlabeld product pattern can match to a labeled product expression, allowing you to ommit labels. For example, `(.x 1, .y 2, .z 3)` can match on the pattern `(a, b, c)`. This operation happens positionally. +An unlabeld product pattern can match to a labeled product expression, allowing you to ommit labels. For example, `(.x 1, .y 2, .z 3)` can match on the pattern `(a, b, c)`. This operation happens positionally. -A labeled tuple pattern must match the label names and the order of a labeled tuple expression for a pattern match. For example, `(.x a, .y b, .z c)` will match with `(.x 1, .y 2, .z 3)` but will not match with `(.y 1, .z 2, .x 3)` because the order does not match. +A labeled tuple pattern must match the label names and the order of a labeled tuple expression for a pattern match. For example, `(.x a, .y b, .z c)` will match with `(.x 1, .y 2, .z 3)` but will not match with `(.y 1, .z 2, .x 3)` because the order does not match. ### Punning -Punning may be useful for labeled tuple patterns, where the label can be used to access the element rather than adding an aditional variable. For example, with punning this code snippit: +Punning may be useful for labeled tuple patterns, where the label can be used to access the element rather than adding an aditional variable. For example, with punning this code snippit: ``` let f = fun(.x, .y) f(.x 1, .y 2) @@ -204,30 +212,30 @@ let f = fun(.x x, .y y) f(.x 1, .y 2) ``` -This would be a great quality of life improvement to patterns with labeled tuples, and will be attempeted with the initial impelemntation of labeled tuples. It will be considered lower priority, since it is not required for labeled tuples patterns. +This would be a great quality of life improvement to patterns with labeled tuples, and will be attempeted with the initial impelemntation of labeled tuples. It will be considered lower priority, since it is not required for labeled tuples patterns. ### Pattern Syntax Errors -Multiple label must be followed by the comma operator, not another label. For example, `.label1 .label2` produces an error.
+Multiple label must be followed by the comma operator, not another label. For example, `.label1 .label2` produces an error.
-Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 p1 .label2 p2` produces an error.
+Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 p1 .label2 p2` produces an error.
Proposed Error Message: Error cursor appears on `.label2`
Expecting an pattern Got a label -Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, the expression `.label1 p1, .label1 p2, .label2 p3, .label1 p4` will have errors on `.label1 p2` and `.label1 p4` +Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, the expression `.label1 p1, .label1 p2, .label2 p3, .label1 p4` will have errors on `.label1 p2` and `.label1 p4` Error Message # What about records? -Records in other languages are very similar to the labeled tuples in this propoasal. Records are typically a data structure that bundles data together with labels and values, and the values are accessed using projection with the labels. The values are unordered in a record, while the values are ordered in a labeled tuple. A labeled tuple is able to perform the same functions as a record, while adding additional functionality by ordering data. If labeled tuples are sucessfully added to Hazel, then records will be redundant in Hazel. +Records in other languages are very similar to the labeled tuples in this propoasal. Records are typically a data structure that bundles data together with labels and values, and the values are accessed using projection with the labels. The values are unordered in a record, while the values are ordered in a labeled tuple. A labeled tuple is able to perform the same functions as a record, while adding additional functionality by ordering data. If labeled tuples are sucessfully added to Hazel, then records will be redundant in Hazel. # Appendix: Other Ideas -While creating this proposal, I considered many other ideas for Hazel labels. These ideas are detailed below. +While creating this proposal, I considered many other ideas for Hazel labels. These ideas are detailed below. Option 1: Use reason like ~label annotations -Option 2: Use a space to separate between label and type/expression/pattern. Period operator is added before label to specify that it is a label. Ties in well with linking the period to labeled products, as the period is also used for projection. Possible problem: Issues with using a period as both binary operator (projection) and unary operator (label definition) -Option 3: Use space operator between labels and type/expression/pattern. Problem: No way to tell distinction between undefined function variable application and labeled expression -Option 4: Use colon operator between labels and type/expression/pattern. Problem: Confusion between type annotations and labeled pair type annotation -Option 5: Use colons and braces to signify a labeled tuple. Problem: This syntax is more typical for a record, and may create confusion about labeled tuples as a value and records as a type definition, as well as create issues if there are any future plans for adding records to Hazel, makes development task larger to define braces syntax +Option 2: Use a space to separate between label and type/expression/pattern. Period operator is added before label to specify that it is a label. Ties in well with linking the period to labeled products, as the period is also used for projection. Possible problem: Issues with using a period as both binary operator (projection) and unary operator (label definition) +Option 3: Use space operator between labels and type/expression/pattern. Problem: No way to tell distinction between undefined function variable application and labeled expression +Option 4: Use colon operator between labels and type/expression/pattern. Problem: Confusion between type annotations and labeled pair type annotation +Option 5: Use colons and braces to signify a labeled tuple. Problem: This syntax is more typical for a record, and may create confusion about labeled tuples as a value and records as a type definition, as well as create issues if there are any future plans for adding records to Hazel, makes development task larger to define braces syntax # Labeled Product Types diff --git a/1-labeled-tuples/ana_1.png b/1-labeled-tuples/ana_1.png new file mode 100644 index 0000000000000000000000000000000000000000..8bca2d0c905d3daa2d8235d6dd0051338a3aedc6 GIT binary patch literal 3858 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 D$H(zB literal 0 HcmV?d00001 diff --git a/1-labeled-tuples/syn_1.png b/1-labeled-tuples/syn_1.png new file mode 100644 index 0000000000000000000000000000000000000000..4363e8b8851af1a9eb1ace8852f9fa4edcc200a9 GIT binary patch literal 6029 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 literal 0 HcmV?d00001 diff --git a/1-labeled-tuples/syn_2.png b/1-labeled-tuples/syn_2.png new file mode 100644 index 0000000000000000000000000000000000000000..10ebf8921d97cf73662e812b8648f92d00bc73ec GIT binary patch literal 5312 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 literal 0 HcmV?d00001 From 112fa42790f2337f17bddb769989e1dba64e191d Mon Sep 17 00:00:00 2001 From: ecdeuts Date: Tue, 12 May 2020 15:28:09 -0400 Subject: [PATCH 07/12] cleaned up document --- 1-labeled-tuples/1-labeled-tuples.md | 160 ++++++++++++++------------- README.md | 7 -- 2 files changed, 86 insertions(+), 81 deletions(-) diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index ca38fda..2dc0981 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -7,6 +7,8 @@ Adding labeled products helps make the tuples become more robust, so more comple Currently only unlabeled tuples are supported in Hazel, and elements can only be accessed positionally using let statements or case statements. # Labeled Product Types +Syntax: `.label1 ty1, .label2 ty2, ..., .labeln tyn` + Files to Edit: UHTyp.re @@ -49,37 +51,28 @@ Bcause a labeld product may still be used with a positional arguments with parti ### Type Syntax Errors -A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error.
-Proposed Error Message: Error Curosr appears on `.label1`
-Expecting a Type Got a Label +* A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error. + * Error Cursor appears on `.label1` + * Expecting a Type Got a Label -A label cannot exist by itself, it is given meaning by having a type follow it. For example, `.label1 ` by itself produces an error.
-Proposed Error Message: Error Curosr appears on `.label1`
-Expecting a Type Got a Label -Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 ty .label2` produces an error.
-Proposed Error Message: Error cursor appears on `.label2`
-Expecting a type Got a label +* A label cannot exist by itself, it is given meaning by having a type follow it. For example, `.label1 ` by itself produces an error. + * Error Cursor appears on `.label1` + * Message: Expecting a Type Got a Label -Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the type `.label1 Num, .label1 Num, .label2 Num, .label1 Bool` will have errors on the second use of `.label1 Num` and `.label1 Bool` -Proposed Error Message: Error Curosr appears on second use of `.label1 Num` and `.label1 Bool`
-Expecting a Unique Label Got a Duplicate Label +* Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 ty .label2` produces an error. + * Error cursor appears on `.label2` + * Message: Expecting a type Got a label - +* Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the type `.label1 Num, .label1 Num, .label2 Num, .label1 Bool` will have errors on the second use of `.label1 Num` and `.label1 Bool` + * Error Cursor appears on second use of `.label1 Num` and `.label1 Bool`
+ * Expecting a Unique Label Got a Duplicate Label # Labeled Tuple Expressions +Syntax: `.label1 e1, .label2 e2, ..., .labeln en` + Files to Edit: UHExp.re To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels. @@ -145,28 +138,42 @@ You press space on `e|.label` and get to `e .label` ### Type Sythesis and Type Analysis Rules for Labeled Product Expressions #### Synthesis -![alt text][Syn Labeled Tuple list.png] -#### Analysis +![Syntheis Rule for Labeled Product](syn_2.png) +![Synthesis Rule for Projection](syn_1.png) + +#### Analysis +![Analysis Rule Right](ana_1.png) +![Analysis Rule Left](ana_2.png) ### Expression Syntax Errors -A label must be followed by a valid expression and comma operator, not another label. For example, `.label1 .label2 e` produces an error.
++ A label must be followed by a valid expression and comma operator, not another label. For example, `.label1 .label2 e` produces an error. + + Proposed Error Message: Error Cursor appears on `.label1` + + Message: Expecting an Expression Got a Label -A label cannot exist by itself, it is given meaning by having an expression follow it. For example, `.label1 ` by itself produces an error.
-Proposed Error Message: Error Curosr appears on `.label1`
-Expecting a Type Got a Label ++ A label cannot exist by itself, it is given meaning by having an expression follow it. For example, `.label1 ` by itself produces an error. + + Error Cursor appears on `.label1`
+ + Message: Expecting an Expression Got a Label -Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 e1 .label2` produces an error.
-Proposed Error Message: Error cursor appears on `.label2`
-Expecting an expression Got a label ++ Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 e1 .label2` produces an error. + + Error cursor appears on `.label2`
+ + Message: Expecting an Expression Got a Label -Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the expression `.label1 1, .label1 3, .label2 4, .label1 True` will have errors on `.label1 3` and `.label1 True` -Error Message ++ Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the expression `.label1 1, .label1 3, .label2 4, .label1 True` will have errors on `.label1 3` and `.label1 True` + + Error cursor appears on `.label1 3` and `.label1 True`
+ + Message: Expecting an Unique Label Got a Duplicate Label + ++ Using the dot opearator as a binary operator on a type that is not a labeled tuple will produce an error. This error will appear on the expression to the left of the dot operator that is not a labeled product. For example, the expression `1.label1` will have an error on `1`. + + Error currsor appears on expression to the left of the dot operator + + Message: Expecting a labeled product Got a (type of expression in error cursor) # Labeled Tuple Patterns -Edited Files: UHPat.re +Syntax: `.label1 p1, .label2 p2, ..., .labeln pn` + +Files to Edit: UHPat.re + To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels. ``` type operator = @@ -196,34 +203,44 @@ Singleton label products are supported. For example, `.x pat1` is supported. ### Sythesis and Analysis -An unlabeld product pattern can match to a labeled product expression, allowing you to ommit labels. For example, `(.x 1, .y 2, .z 3)` can match on the pattern `(a, b, c)`. This operation happens positionally. +An unlabeled product pattern can match to a labeled product expression, allowing you to ommit labels. For example, `(.x 1, .y 2, .z 3)` can match on the pattern `(a, b, c)`. This operation happens positionally. A labeled tuple pattern must match the label names and the order of a labeled tuple expression for a pattern match. For example, `(.x a, .y b, .z c)` will match with `(.x 1, .y 2, .z 3)` but will not match with `(.y 1, .z 2, .x 3)` because the order does not match. +A partially labled pattern can match with a fully labled expression as long as the labels that do exist match. For example, `(.x 1, .y 2, .z 3)` will match on `(.x p1, p2, .z p3)` + ### Punning Punning may be useful for labeled tuple patterns, where the label can be used to access the element rather than adding an aditional variable. For example, with punning this code snippit: + ``` let f = fun(.x, .y) +... f(.x 1, .y 2) ``` + would be equivalent to + ``` let f = fun(.x x, .y y) +... f(.x 1, .y 2) ``` -This would be a great quality of life improvement to patterns with labeled tuples, and will be attempeted with the initial impelemntation of labeled tuples. It will be considered lower priority, since it is not required for labeled tuples patterns. +This would be a great quality of life improvement to patterns with labeled tuples, and will be attempeted with the initial impelemntation of labeled tuples. It will be considered lower priority, since it is not required for labeled tuples patterns to function at a basic level. ### Pattern Syntax Errors -Multiple label must be followed by the comma operator, not another label. For example, `.label1 .label2` produces an error.
++ Multiple label must be followed by the comma operator, not another label. For example, `.label1 .label2` produces an error.
+ + Error cursor appears on `.label 2` + + Message: Expecting a Pattern Got a Label -Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 p1 .label2 p2` produces an error.
-Proposed Error Message: Error cursor appears on `.label2`
-Expecting an pattern Got a label ++ Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 p1 .label2 p2` produces an error.
+ + Error cursor appears on `.label2`
+ + Message: Expecting a Pattern Got a Label -Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, the expression `.label1 p1, .label1 p2, .label2 p3, .label1 p4` will have errors on `.label1 p2` and `.label1 p4` -Error Message ++ Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, the expression `.label1 p1, .label1 p2, .label2 p3, .label1 p4` will have errors on `.label1 p2` and `.label1 p4` + + Error cursor appears on `.label2`
+ + Message: Expecting a Unique Label Got a Duplicate Label # What about records? Records in other languages are very similar to the labeled tuples in this propoasal. Records are typically a data structure that bundles data together with labels and values, and the values are accessed using projection with the labels. The values are unordered in a record, while the values are ordered in a labeled tuple. A labeled tuple is able to perform the same functions as a record, while adding additional functionality by ordering data. If labeled tuples are sucessfully added to Hazel, then records will be redundant in Hazel. @@ -231,43 +248,38 @@ Records in other languages are very similar to the labeled tuples in this propoa # Appendix: Other Ideas While creating this proposal, I considered many other ideas for Hazel labels. These ideas are detailed below. -Option 1: Use reason like ~label annotations -Option 2: Use a space to separate between label and type/expression/pattern. Period operator is added before label to specify that it is a label. Ties in well with linking the period to labeled products, as the period is also used for projection. Possible problem: Issues with using a period as both binary operator (projection) and unary operator (label definition) -Option 3: Use space operator between labels and type/expression/pattern. Problem: No way to tell distinction between undefined function variable application and labeled expression -Option 4: Use colon operator between labels and type/expression/pattern. Problem: Confusion between type annotations and labeled pair type annotation -Option 5: Use colons and braces to signify a labeled tuple. Problem: This syntax is more typical for a record, and may create confusion about labeled tuples as a value and records as a type definition, as well as create issues if there are any future plans for adding records to Hazel, makes development task larger to define braces syntax +### Reason like ~label annotations +Types: `~label1: ty1, ~label2: ty2,..., ~labeln: tyn` -# Labeled Product Types +Expressions: `~label1: ty1, ~label2: ty2, ..., ~labeln: tyn` + +Patterns: `~label: ty1, ~label: ty2,..., ~labeln: tyn` + +This was very similar to the final dot notation used. However, the dot opearator was chosen over the tilda operator since the tilda key is harder to acces than the dot on a keyboard, and the dot operator was already associated with projection so it made sense to associate it with label annotations as well. + +### Space Separator with No Label Annotations +Types: `label1 ty1, label2 ty2, ..., labeln tyn` + +Expressions: `label1 e1, label2: e2, ..., labeln: en` + +Patterns: `label1 p1, label2 p2, ..., labeln pn` + +This suggestion reduces the amount of additional operators needed for labled products. However, there is no way to tell distinction between undefined function variable application and labeled expression, so this syntax would not work. -Currently: `ty1, ty2, ..., tyn` -With Labels: `~label1: ty1, ~label2: ty2,..., ~labeln: tyn` -With labels: `.label1 ty1, .label2 ty2, ..., .labeln tyn` -With labels: `label1 ty1, label2 ty2, ..., labeln tyn` -With Labels: `label1: ty1, label2: ty2, ..., labeln: tyn` -With labels: `{label1: ty1, label2:ty2, ..., labeln:tyn}' +### Colon Operator +Types: `label1: ty1, label2: ty2, ..., labeln: tyn` -# Labeled Product Expressions +Expressions: `label1: e1, label2: e2, ..., labeln: en` -Currently: `e1, e2, ..., en` -With labels: `~label1=ty1, ~label2=ty2, ..., ~labeln=tyn` -With Labels: `.label1 e1, .label2 e2, ..., .labeln en` -With Labels: `label1 e1, label2: e2, ..., labeln: en` -With Labels: `label1: e1, label2: e2, ..., labeln: en` -With labels: `{label1: e1, label2:e2, ..., labeln:e2}' +Patterns: `label1: p1, label2: p2, ..., labeln: pn` -# Labeled Product Patterns -Currently: `p1, p2, ..., pn` -With Labels: `~label=ty1, ~label=ty2,..., ~labeln=tyn` -With Labels: `.label1 p1, .label2 p2, ..., .labeln pn` -With Labels: `label1 p1, label2 p2, ..., labeln pn` -With Labels: `label1: p1, label2: p2, ..., labeln: pn` -With labels: `{label1: p1, label2: p2, ..., labeln: pn}' +This syntax imitates many other languages, which use a colon operator to separate labels and values in record types. However, this creates onfusion between labeled pair type annotation and type annotations as they both would use the colon operator. For this reason, this option was not used. -In pattern position, we would also want to support type annotations. +### Colons and Braces +Types: `{label1: ty1, label2:ty2, ..., labeln:tyn}` -# Projection +Expressions: `{label1: e1, label2:e2, ..., labeln:e2}` -Currently: no projection -With Labels: `e.label` +Patterns: `{label1: p1, label2: p2, ..., labeln: pn}` -(For many of these, we will need label holes.) +This syntax is more typical for a record, and may create confusion about labeled tuples as a value and records as a type definition. In addition, adding logic for braces within Hazel would increase implementation complexity a great deal. \ No newline at end of file diff --git a/README.md b/README.md index eb4142f..1514534 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,3 @@ -<<<<<<< HEAD -# Creating a Proposal for Hazel Improvement (PHI) -* Create a new directory with a short name, e.g. `#-labeled-tuples`, where `#` is the next unused number starting at 1. -* Create a `#-labeled-tuples.md` file in that directory with the proposal in it. -* We may require a specific format in the future. -======= # Motivation As the Hazel developer community grows, it is important that new features are vetted and documented. We will be using a proposal process for new Hazel features, following the pattern in other language communities, e.g. @@ -32,4 +26,3 @@ At the moment, we are proceeding less formally than those processes. This will l # Pronunciation PHI is pronounced however you'd like to pronounce the greek letter "phi" (like "pie" or "fee"). ->>>>>>> 896b759abd7703bb1aa55e26f8b07f18e59f86db From bd43809c8ca40358240d6b8efe37bb0017c0f085 Mon Sep 17 00:00:00 2001 From: ecdeuts Date: Tue, 19 May 2020 11:32:51 -0400 Subject: [PATCH 08/12] added all comments from draft pr --- 1-labeled-tuples/1-labeled-tuples.md | 99 ++++++++------------------- 1-labeled-tuples/ana_1.png | Bin 3858 -> 9346 bytes 1-labeled-tuples/ana_2.png | Bin 4043 -> 18919 bytes 1-labeled-tuples/ana_2_old.png | Bin 0 -> 4043 bytes 1-labeled-tuples/syn_1.png | Bin 6029 -> 12574 bytes 1-labeled-tuples/syn_2.png | Bin 5312 -> 9024 bytes 6 files changed, 30 insertions(+), 69 deletions(-) create mode 100644 1-labeled-tuples/ana_2_old.png diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index 2dc0981..205ed7c 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -1,11 +1,11 @@ # Introduction -Labeled products are a value similar to products, but some/all elements have a label. This label can be used then for projection. This allows elements within the product can be accessed either positionally or by the label. +Labeled products are similar to products, but some or all elements have a label. This label can be used then for projection. This allows elements within the product to be accessed either positionally or by the label. -Adding labeled products helps make the tuples become more robust, so more complex products can be easily used. Accesing a longer tuple using only positional arguments adds unneccsary bulk to the code. Having labels allows for easy access of values in a product. The labeled products can also serve a similar use as records in other languages. +Adding labeled products helps with readability of products, so more complex products can be easily used. Remembering the positions of values in along product may be difficult. Having labels allows for easy access of values in a product. The labeled products serves a similar purpose as records in other languages. -Currently only unlabeled tuples are supported in Hazel, and elements can only be accessed positionally using let statements or case statements. +Currently only unlabeled tuples are supported in Hazel, and elements can only be accessed positionally using pattern matching (via let or case) # Labeled Product Types Syntax: `.label1 ty1, .label2 ty2, ..., .labeln tyn` @@ -19,23 +19,15 @@ Files to Edit: UHTyp.re To add labeled product types, the operator and opearnd types will need to be expanded like so: ``` type operator = - | Arrow - | Prod - | Sum +... | Space; ``` Space will be left associateive and have the highest precedence. ``` type operand = - | Hole - | Unit - | Int - | Float - | Bool - | Parenthesized(t) - | List(t) - | Label; +... + | Label(Label.t); ``` @@ -52,7 +44,7 @@ Bcause a labeld product may still be used with a positional arguments with parti ### Type Syntax Errors * A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error. - * Error Cursor appears on `.label1` + * Error Cursor appears on `.label2` * Expecting a Type Got a Label @@ -62,11 +54,11 @@ Bcause a labeld product may still be used with a positional arguments with parti * Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 ty .label2` produces an error. - * Error cursor appears on `.label2` - * Message: Expecting a type Got a label + * Error cursor appears on space operator + * Message: Unexpected Label * Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the type `.label1 Num, .label1 Num, .label2 Num, .label1 Bool` will have errors on the second use of `.label1 Num` and `.label1 Bool` - * Error Cursor appears on second use of `.label1 Num` and `.label1 Bool`
+ * Error Cursor appears on second and third use of `.label1`
* Expecting a Unique Label Got a Duplicate Label # Labeled Tuple Expressions @@ -78,37 +70,15 @@ Files to Edit: UHExp.re To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels. ``` type operator = - | Space - | Plus - | Minus - | Times - | FPlus - | FMinus - | FTimes - | LessThan - | GreaterThan - | Equals - | Comma - | Cons - | And - | Or + ... | Dot; ``` The Dot operator will be left associative and have highest precedence. ``` operand = - | EmptyHole(MetaVar.t) - | Var(ErrStatus.t, VarErrStatus.t, Var.t) - | IntLit(ErrStatus.t, string) - | FloatLit(ErrStatus.t, string) - | BoolLit(ErrStatus.t, bool) - | ListNil(ErrStatus.t) - | Lam(ErrStatus.t, UHPat.t, option(UHTyp.t), t) - | Inj(ErrStatus.t, InjSide.t, t) - | Case(ErrStatus.t, t, rules, option(UHTyp.t)) - | Parenthesized(t) - | ApPalette(ErrStatus.t, PaletteName.t, SerializedModel.t, splice_info) - | Label(t) + ... + | Label(Label.t) + | Prj(UHExp.t, Label.t) ``` @@ -130,7 +100,7 @@ Some languages, such as Reason, have record punning. This is where a record's la ### Projection Expressions Labels can be used to access elements of a pair through projection expressions. -`e.label` will be the new expression form. It will use the dot operator, which was already added to the operator type above. `e.label` expects `e` to be a labeled tuple type and `label` to match one of the labels within `e`. `e.label` will retun the value that has the label `label`. +`e.label` will be the new expression form. It will use the dot operator, which was already added to the operator type above. `e.label` expects `e` to synthesize to a labeled tuple type and `label` to match one of the labels within `e`. `e.label` will retun the value that has the label `label`. #### Backspace You press backspace on `e |.label` and get to `e.label` @@ -143,14 +113,14 @@ You press space on `e|.label` and get to `e .label` ![Synthesis Rule for Projection](syn_1.png) #### Analysis -![Analysis Rule Right](ana_1.png) - -![Analysis Rule Left](ana_2.png) +![Analysis Rule Single](ana_1.png) +![Analysis Rule Tuple](ana_2.png) ### Expression Syntax Errors +Files to Edit: CursorInfo.re + A label must be followed by a valid expression and comma operator, not another label. For example, `.label1 .label2 e` produces an error. - + Proposed Error Message: Error Cursor appears on `.label1` + + Proposed Error Message: Error Cursor appears on `.label2` + Message: Expecting an Expression Got a Label + A label cannot exist by itself, it is given meaning by having an expression follow it. For example, `.label1 ` by itself produces an error. @@ -158,11 +128,11 @@ You press space on `e|.label` and get to `e .label` + Message: Expecting an Expression Got a Label + Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 e1 .label2` produces an error. - + Error cursor appears on `.label2`
- + Message: Expecting an Expression Got a Label + + Error cursor appears on space operator
+ + Message: Unexpected Label + Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the expression `.label1 1, .label1 3, .label2 4, .label1 True` will have errors on `.label1 3` and `.label1 True` - + Error cursor appears on `.label1 3` and `.label1 True`
+ + Error cursor appears on second and third use of `.label1`
+ Message: Expecting an Unique Label Got a Duplicate Label + Using the dot opearator as a binary operator on a type that is not a labeled tuple will produce an error. This error will appear on the expression to the left of the dot operator that is not a labeled product. For example, the expression `1.label1` will have an error on `1`. @@ -177,23 +147,14 @@ Files to Edit: UHPat.re To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels. ``` type operator = - | Comma - | Space +... | Dot; ``` The Dot operator will be left associative and have highest precedence. ``` and operand = - | EmptyHole(MetaVar.t) - | Wild(ErrStatus.t) - | Var(ErrStatus.t, VarErrStatus.t, Var.t) - | IntLit(ErrStatus.t, string) - | FloatLit(ErrStatus.t, string) - | BoolLit(ErrStatus.t, bool) - | ListNil(ErrStatus.t) - | Parenthesized(t) - | Inj(ErrStatus.t, InjSide.t, t); - | Label(ErrStatus.t, string) + ... + | Label(LabelErrStatus.t, string) ``` Partially labeled product patterns are allowed, and labels and non-labeled positions can be interleaved. @@ -231,15 +192,15 @@ This would be a great quality of life improvement to patterns with labeled tuple ### Pattern Syntax Errors + Multiple label must be followed by the comma operator, not another label. For example, `.label1 .label2` produces an error.
- + Error cursor appears on `.label 2` + + Error cursor appears on `.label2` + Message: Expecting a Pattern Got a Label + Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 p1 .label2 p2` produces an error.
- + Error cursor appears on `.label2`
- + Message: Expecting a Pattern Got a Label + + Error cursor appears on space operator
+ + Message: Unexpected Label -+ Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, the expression `.label1 p1, .label1 p2, .label2 p3, .label1 p4` will have errors on `.label1 p2` and `.label1 p4` - + Error cursor appears on `.label2`
++ Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, the expression `.label1 p1, .label1 p2, .label2 p3, .label1 p4` will have errors on the second and third use of `.label1` and `.label1` + + Error cursor appears on second and third use of `.label1`
+ Message: Expecting a Unique Label Got a Duplicate Label # What about records? diff --git a/1-labeled-tuples/ana_1.png b/1-labeled-tuples/ana_1.png index 8bca2d0c905d3daa2d8235d6dd0051338a3aedc6..edee572e0cad63c906ae2243ce4282701c1c819d 100644 GIT binary patch literal 9346 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 literal 3858 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 Ufwftn_#X>!adda6wY#1AUjiy#*qn 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 S!n{O+4XP@d4^a25BK{YaaU+-j literal 4043 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 D$H(zB diff --git a/1-labeled-tuples/ana_2_old.png b/1-labeled-tuples/ana_2_old.png new file mode 100644 index 0000000000000000000000000000000000000000..ae61347dbe1a8de391ea40b600360ee1a939c305 GIT binary patch literal 4043 zcmc(ic{r4B+s8*`iHH_{l!Ppiro~eBUC1b6GK?kb*t0g4QL^=uS&-3#=uNU_~Cj7i&yZ``z z-}H{56#&3t$F^VaaIwdPR&!nUizC>|L?3_|I={qrj(O@?=m7v9()jjVINAR3z&m!q z0KlciKMzN&E9ZFt;H0yuq27Zhj&#y++8Lvxy}u{7B(Cx0y}TaRW9WL~_|->(0)c}1 zn%PNq47Wld)?@M!d6V>yPlSaFkBii$J2NgO<#_#&l6>m+LNa?!Z2t3iDKe1Ils{Qn z;6YnjA)=^DD=b8YhmS{OWJG0Iegy{OZ!CO@3n18YIBf~gJr;KbU}*T|h_2y(((s=D zid4iL8|RixhTQw)Khs8}ky`OuN5_w{CkXYhOk$&7?(I1MXZ{PaTM-;%{1_$r@>_58eevHmw)JH3EmUgNZQy3c2L=M>E)$(hh zCw+;vJ(^F}K3#Ho6t+4;M{IoQO*sec&$e&!ZysBdM=$Gc#?1Hf*SYoyY`wf5bHFNV zhHsQAq0b$?WAMe6(7M|0b5s>3^QOoot;KT+ij9~+zO-xdM=9DQf*#5^{kmUTyx{L7 z9X3)qy!*31b7fQ-U*i;B;*Ha)e3o8aep(Jx4>9da6~Czn#?&vQgUa9D4(`>u;XxTf zVU*7cT+k$V>k0gDBjBB4=w@`2GrC@vU_#}V$IlksKkD6+nwpvuxwWz{=N4LCd5^Wy zx=Nd0T7pge5L2z>=B%cgm6n!Twc0#do4WIhLb2}P;egbh4Oy9P#tot87#cMRu%&Qb zaHyobvz)B#AdN=5$3?qX(J>t$9k0oe?9W5w-C4DYNRpc`Rf@mi ztwjx*_1mwil<-$87QUD|cG!cfzSyzBbfx6x=LeiKpGtFQN-=NQS-5joZU6p|6M^M% z8<{$`@MzigUPqWV{R<3y8Ch{$L^{OkPQvm?vV!mFSIOE$t})Rq6(3x7n$7{?ymk~J z@2_*?&MZV)rj1VhPO;2!!uW6W2NE_Ck9>)RSqRxo%F2tdlV$RD-C}|aN}A8M#?jA2 z+-otbH-p;!@bnPE$Km}<7AS;Y!Fgc_rGcq`h&NIW&AligX|Fdaisciz`q4^*Gj*s+ zLI*M3#+>w7A)09KEEe_ByLXxNIuWlEH=Gy9U5OaC!Acvn1MG3G?`%6sVAbqf*a1TwTMNT{>KJZq4(LE*meex2Z&)|_!&=U}^N zzvBAfq%66l@oB?Tv$5mietG_xpuCV7A%)})o5IqTG1Gd5kr8yD{kEyJK!j)zK90Rn zy_=$0b;BjYsTKi4IY`J-`3|#FL!bXB$`E~Ivxdr}4<@|;IWKvrw3vfOwIL@?u0XF{ z8V4_~27i*R;cDy;d?&*P5E7~d2ntF5Z-bu#bX@cNV3f9T6>p^Jn@R2z#3YOz3WY6> zNN$yDq_kqAShbOH*#z0H7wMc&lNPT6o+k0w0g{sbc>iuF+y;fYxpgA}C(xxQ$Yp=F zecU6$CYrf0KuXGurHk#w0Bl(iirM!f`k@b0jyO%Km^?XH-3t(;|^ za&U04hp+FTR^4{~IC5d`^K<5AUtb^TW-n%dI)Nq?eO@%dIy49Mu%mr1wXd1lC>4NRne7N@6&>HviaBVD6xPiv;2|#KYg#j|4{L6`WG`ixb*PN1 zsxM*A>^ZpD@eGD)kJwo%`&MCHHeCn!+dJwDb&dJ?Id`LG`N2JL+vFV&FvbBk@Z7f8 zaeTEhP%C6H9ln4BvrD%M+ei6>#q)r5Wo@@E9OTK7$}7AImU=d4ji?Jm&wLeN`*z`* zH*c=9(Q=aw;)dZGNW<3y!*D9(cF@nH$T%0=cKSZOY1W}XTgkrhqZORZiFvaLYMPQ2 z&^y$rJ&Nc%S>LbqTahcn2R@ReqY!{vO4KO!k3{}1uQ-%r*0Drs@i%g652)sEnt?Ckd&KSv|HnsZ9a%0$=%q;E(dwq3~X@ikNE z{{DX4?9SHNF1ALXF^n8`mN4NH%`wsYGaZL|W9sEY4ItA`EuLs42a01^+pyLJSjZP| zxlM_`rCi->J`;!u6nJ#9Y*Be_xs4|iB8U^5HDaF&TugjG;ot@1O6)E zThj&Fw5XI&V%-bZ8fVK9N>M2fIV`3mnCB2dttg|dhdwOrii%N<*;*m_$>p{0Gws1U zz!>?QV`(f}-LRF(F)tE!swtq=s@0L|F8Dwvpq*8!mC#dRo-Qmg zXfncc;?>!=WOA@$U;+m+T>k6@eQ#(>wSl7-jIz0Eq@k;n`c|X3Z3_MB;(}D1YhNlGkTvZ)m5L?iVNu|(+ONi3+@A2j zx7Wynpbkd14fmtk^y z#XAmmmK)zj*=4iqco@}ebVPni z3(WV6FqTL1ggBJ+%4q&Lwhi8uX|7I0hQ`urIu3$Ln5WeXukqUtPZp?v?sHTKZ&%wl z`7Vcfc=Yc5?vr3%GJdV+^!6W_^R4L9P7(QRvHTdF?-ad>tj_)UemVgSN^+m5D0^yq z%ZDllEhcvqr%LF|Fp1@Lf#CIo#&_xGaUhYnkI8|aAonja9MvZ1a zxLm`BZwPkOd1Y$t81q=jXj#VmrMBH>$BsL*DBos)Z+F<00aT@TgFo^!5D_-UDExg_ z`&yS6FPwXU_hn&n&HHs#|LH}urB2}>9I8ou*I$FOzq{H2t6Ezi8!esW(TQS3uJc|a^Yl@5$sszBADBa5n zinnwQ_cn0HrTcm1QJ;QqcykY`SM8G%B^>$*h+e70Pv#Bd5fyymwaXY6^`9200NP(8 zgwA)>txgD54|1~axu>Wh3U488&^Y^?J~25#KWJ+cSI{)b4Y&G9Bi6Bn-aY`kVD|XI zzEs?Tl|-TOgthiQxQX}7J8Bz9OthB#qL_WI z8RUArN)^y%U-;YXq5A8d$gZRMd(PaGU5UBw0ixOv6@^kkhB;u^!E1r1tqRWgdisY z@vsPPf%9H`5Nv|JIaDRWV#3bmq($@yF6A)e^aQrCf!dZe%x!h$LALF%CH4fjX{$_u zEXn+0%4?KrN5ZM48wR6muj=89Ch~|l|7Yr3ljV8J==$EW%(GDlLik&eqzY<)UydKu ze@=hg2b(n0l;8_9ij^m2deQT2_z+0Av9sO@Be3v~DLvZE+$ zZ}vVVnH}XZc)&!}^@7P}m5!5w@#rH(H|v!>CWebpTJ#xC#0804J9A-Ni8wiWK;3re zcnfQxylP?V#!N$2gb?QS(dga>!!9V`0$-+jfLdWp z1}}%0={_riwpM~Fkq8@yxAt!JANh3g|MYIj#$z8R0|D5pjw9JW0`K13NmjS)TRfut zH->8?OTm+UY5Ey7qFpdl_dnl}IRCxz`!CI;TtDO%z#hT&5Vj227jS^75y%ju?;QIt D$H(zB literal 0 HcmV?d00001 diff --git a/1-labeled-tuples/syn_1.png b/1-labeled-tuples/syn_1.png index 4363e8b8851af1a9eb1ace8852f9fa4edcc200a9..1003b15d88062e740fcc114ad9e241f425040683 100644 GIT binary patch literal 12574 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 diff --git a/1-labeled-tuples/syn_2.png b/1-labeled-tuples/syn_2.png index 10ebf8921d97cf73662e812b8648f92d00bc73ec..3ec47238ea515475c4c6ed7e49babe8342ea79e8 100644 GIT binary patch literal 9024 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 From a2cbd86df596963569317d4f13d2d39f52904907 Mon Sep 17 00:00:00 2001 From: ecdeuts Date: Tue, 19 May 2020 14:43:45 -0400 Subject: [PATCH 09/12] cleaned up and spell checked --- 1-labeled-tuples/1-labeled-tuples.md | 136 +++++++++++++++------------ 1 file changed, 74 insertions(+), 62 deletions(-) diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index 205ed7c..ca056a8 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -1,11 +1,11 @@ # Introduction -Labeled products are similar to products, but some or all elements have a label. This label can be used then for projection. This allows elements within the product to be accessed either positionally or by the label. +Labeled products are a type of value. They are similar to products, but some or all elements have a label. The label is used with projection. This allows elements within the product to be accessed either positionally or by the label. -Adding labeled products helps with readability of products, so more complex products can be easily used. Remembering the positions of values in along product may be difficult. Having labels allows for easy access of values in a product. The labeled products serves a similar purpose as records in other languages. +Adding labeled products helps with readability of products, so more complex products can be easily used within Hazel. Remembering the positions of values in along product may be difficult, so labels allow for easy access of values in a product. The labeled products serve a similar purpose as records in other languages. -Currently only unlabeled tuples are supported in Hazel, and elements can only be accessed positionally using pattern matching (via let or case) +Currently only unlabeled tuples are supported in Hazel, and elements can only be accessed positionally using pattern matching (via let or case). # Labeled Product Types Syntax: `.label1 ty1, .label2 ty2, ..., .labeln tyn` @@ -38,28 +38,26 @@ Singleton label products are supported. For example, `.x Num` is supported. ### Type Equivalence -Bcause a labeld product may still be used with a positional arguments with partially labeld types, the type equivalence considers the order of the labels with equlivalence. For example, `(.x Num, .y Num, .z Num) != (.z Num, .y Num, .x Num)` because the order of the labels is different. - +A labeled product may still be used with positional arguments, so the type equivalence considers the order of the labels with equlivalence. For example, `(.x Num, .y Num, .z Num) != (.z Num, .y Num, .x Num)` because the order of the labels is different. ### Type Syntax Errors +Files to Edit: CursorInfo.re * A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error. - * Error Cursor appears on `.label2` - * Expecting a Type Got a Label - - -* A label cannot exist by itself, it is given meaning by having a type follow it. For example, `.label1 ` by itself produces an error. - * Error Cursor appears on `.label1` - * Message: Expecting a Type Got a Label + * Error Cursor appears on `.label2` + * Expecting a Type Got a Label +* A label cannot exist by itself; it is given meaning by having a type follow it. For example, `.label1 ` by itself produces an error. + * Error Cursor appears on `.label1` + * Message: Expecting a Type Got a Label * Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 ty .label2` produces an error. - * Error cursor appears on space operator - * Message: Unexpected Label + * Error cursor appears on space operator + * Message: Expecting ? Got an Unexpected Label * Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the type `.label1 Num, .label1 Num, .label2 Num, .label1 Bool` will have errors on the second use of `.label1 Num` and `.label1 Bool` - * Error Cursor appears on second and third use of `.label1`
- * Expecting a Unique Label Got a Duplicate Label + * Error Cursor appears on second and third use of `.label1`
+ * Expecting a Unique Label Got a Duplicate Label # Labeled Tuple Expressions @@ -67,7 +65,7 @@ Syntax: `.label1 e1, .label2 e2, ..., .labeln en` Files to Edit: UHExp.re -To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels. +To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels and projections. ``` type operator = ... @@ -88,27 +86,40 @@ For example, the labeled product expression `(.x 2, 3, .y True)` is allowed. Singleton label product expressions are supported. For example, `.x 2` is supported. -An unlabeld product expression can analyze to a labeled product expression, allowing you to omit labels. For example, `(1, 2, 3) <= (.x Num, .y Num, .z Num)` is valid and each value in `(1,2,3)`. This operation happens positionally, and does not assign labels based on variable name if variables are used. For example, `(y, x, z) <= (.x Num, .y Num, .z Num)` is valid. +An unlabeled product expression can analyze to a labeled product expression, allowing you to omit labels. For example, `(1, 2, 3) <= (.x Num, .y Num, .z Num)` is valid and each value in `(1,2,3)`. This operation happens positionally, and does not assign labels based on variable name if variables are used. For example, `(y, x, z) <= (.x Num, .y Num, .z Num)` is valid. ### Punning -Some languages, such as Reason, have record punning. This is where a record's labels can be implied when it is declared using variables. For example, `{x, y, z} => {x: x, y: y, z: z}` is true. Similar punning fuctionality could be implemented in Hazel. For example, if this punnign was implemented `(x, y, z) => (x: x, y: y, z: z)` would hold true. However, this creates a question of if every tuple created with variables should be a labeled tuple. Given this additional complexity and added development costs, I believe that labeled tuple punning should be considered out of scope for the inital addition of labeled tuples. +Some languages, such as Reason, have record punning. This is where a record's labels can be implied when it is declared using variables. For example, `{x, y, z} => {x: x, y: y, z: z}` is true. Similar punning fuctionality could be implemented in Hazel. For example, if this punning was implemented `(x, y, z) => (x: x, y: y, z: z)` would hold true. However, this creates a question of if every tuple created with variables should be a labeled tuple. Given this additional complexity and added development costs, I believe that labeled tuple punning should be considered out of scope for labeled tuples. ### Projection Expressions -Labels can be used to access elements of a pair through projection expressions. + +Syntax: `e.label` + +Files to Edit: UHExp.re + +Labels can be used to access elements of a pair through projection expressions. To add projection, the operand type must be extended to include projection. -`e.label` will be the new expression form. It will use the dot operator, which was already added to the operator type above. `e.label` expects `e` to synthesize to a labeled tuple type and `label` to match one of the labels within `e`. `e.label` will retun the value that has the label `label`. +``` +operand = + ... + | Prj(UHExp.t, Label.t) + ``` + +`e.label` will be the new expression form. `e.label` expects `e` to synthesize to a labeled tuple type and `label` to match one of the labels within `e`. + +`e.label` will return the value that has the label `label`. #### Backspace -You press backspace on `e |.label` and get to `e.label` +You can press backspace on `e |.label` and get to `e.label` -You press space on `e|.label` and get to `e .label` +You can press space on `e|.label` and get to `e .label` ### Type Sythesis and Type Analysis Rules for Labeled Product Expressions #### Synthesis -![Syntheis Rule for Labeled Product](syn_2.png) +![Synthesis Rule for Labeled Product](syn_2.png) ![Synthesis Rule for Projection](syn_1.png) @@ -117,27 +128,27 @@ You press space on `e|.label` and get to `e .label` ![Analysis Rule Tuple](ana_2.png) ### Expression Syntax Errors - Files to Edit: CursorInfo.re + + A label must be followed by a valid expression and comma operator, not another label. For example, `.label1 .label2 e` produces an error. - + Proposed Error Message: Error Cursor appears on `.label2` - + Message: Expecting an Expression Got a Label + + Proposed Error Message: Error Cursor appears on `.label2` + + Message: Expecting an Expression Got a Label -+ A label cannot exist by itself, it is given meaning by having an expression follow it. For example, `.label1 ` by itself produces an error. - + Error Cursor appears on `.label1`
- + Message: Expecting an Expression Got a Label ++ A label cannot exist by itself; it is given meaning by having an expression follow it. For example, `.label1 ` by itself produces an error. + + Error Cursor appears on `.label1`
+ + Message: Expecting an Expression Got a Label + Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 e1 .label2` produces an error. - + Error cursor appears on space operator
- + Message: Unexpected Label + + Error cursor appears on space operator
+ + Message: Expecting ? Got an Unexpected Label -+ Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the expression `.label1 1, .label1 3, .label2 4, .label1 True` will have errors on `.label1 3` and `.label1 True` - + Error cursor appears on second and third use of `.label1`
- + Message: Expecting an Unique Label Got a Duplicate Label ++ Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, `.label1 1, .label1 3, .label2 4, .label1 True` will produce an error. + + Error cursor appears on second and third use of `.label1`
+ + Message: Expecting a Unique Label Got a Duplicate Label -+ Using the dot opearator as a binary operator on a type that is not a labeled tuple will produce an error. This error will appear on the expression to the left of the dot operator that is not a labeled product. For example, the expression `1.label1` will have an error on `1`. - + Error currsor appears on expression to the left of the dot operator - + Message: Expecting a labeled product Got a (type of expression in error cursor) ++ Using the dot operator as a binary operator on a type that is not a labeled tuple will produce an error. This error will appear on the expression to the left of the dot operator that is not a labeled product. For example, the expression `1.label1` will produce an error + + Error cursor appears on`1` + + Message: Expecting a Labeled Product Got a Num # Labeled Tuple Patterns Syntax: `.label1 p1, .label2 p2, ..., .labeln pn` @@ -158,17 +169,17 @@ and operand = ``` Partially labeled product patterns are allowed, and labels and non-labeled positions can be interleaved. -For example, the labeled product type `(.x pat1, pat2, .y pat3)` is allowed. +For example, the labeled product type `(.x p1, p2, .y p3)` is allowed. -Singleton label products are supported. For example, `.x pat1` is supported. +Singleton label products are supported. For example, `.x p1` is supported. -### Sythesis and Analysis +### Synthesis and Analysis An unlabeled product pattern can match to a labeled product expression, allowing you to ommit labels. For example, `(.x 1, .y 2, .z 3)` can match on the pattern `(a, b, c)`. This operation happens positionally. A labeled tuple pattern must match the label names and the order of a labeled tuple expression for a pattern match. For example, `(.x a, .y b, .z c)` will match with `(.x 1, .y 2, .z 3)` but will not match with `(.y 1, .z 2, .x 3)` because the order does not match. -A partially labled pattern can match with a fully labled expression as long as the labels that do exist match. For example, `(.x 1, .y 2, .z 3)` will match on `(.x p1, p2, .z p3)` +A partially labeled pattern can match with a fully labled expression as long as the labels that do exist match. For example, `(.x 1, .y 2, .z 3)` will match on `(.x p1, p2, .z p3)` ### Punning Punning may be useful for labeled tuple patterns, where the label can be used to access the element rather than adding an aditional variable. For example, with punning this code snippit: @@ -187,45 +198,46 @@ let f = fun(.x x, .y y) f(.x 1, .y 2) ``` -This would be a great quality of life improvement to patterns with labeled tuples, and will be attempeted with the initial impelemntation of labeled tuples. It will be considered lower priority, since it is not required for labeled tuples patterns to function at a basic level. +This would be a great quality of life improvement to patterns with labeled tuples, and will be attempeted with the initial implementation of labeled tuples. It will be considered lower priority, since it is not required for labeled tuples patterns to function at a basic level. ### Pattern Syntax Errors +Files to Edit: CursorInfo.re -+ Multiple label must be followed by the comma operator, not another label. For example, `.label1 .label2` produces an error.
- + Error cursor appears on `.label2` - + Message: Expecting a Pattern Got a Label ++ Multiple labels must be followed by the comma operator, not another label. For example, `.label1 .label2` produces an error.
+ + Error cursor appears on `.label2` + + Message: Expecting a Pattern Got a Label + Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 p1 .label2 p2` produces an error.
- + Error cursor appears on space operator
- + Message: Unexpected Label + + Error cursor appears on space operator
+ + Message: Expecting ? Got an Unexpected Label -+ Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, the expression `.label1 p1, .label1 p2, .label2 p3, .label1 p4` will have errors on the second and third use of `.label1` and `.label1` - + Error cursor appears on second and third use of `.label1`
- + Message: Expecting a Unique Label Got a Duplicate Label ++ Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, `.label1 p1, .label1 p2, .label2 p3, .label1 p4` produces an error. + + Error cursor appears on second and third use of `.label1`
+ + Message: Expecting a Unique Label Got a Duplicate Label -# What about records? +# What About Records? Records in other languages are very similar to the labeled tuples in this propoasal. Records are typically a data structure that bundles data together with labels and values, and the values are accessed using projection with the labels. The values are unordered in a record, while the values are ordered in a labeled tuple. A labeled tuple is able to perform the same functions as a record, while adding additional functionality by ordering data. If labeled tuples are sucessfully added to Hazel, then records will be redundant in Hazel. # Appendix: Other Ideas While creating this proposal, I considered many other ideas for Hazel labels. These ideas are detailed below. -### Reason like ~label annotations -Types: `~label1: ty1, ~label2: ty2,..., ~labeln: tyn` +### Reason Like ~label Annotations +Types: `~label1: ty1, ~label2: ty2, ... , ~labeln: tyn` -Expressions: `~label1: ty1, ~label2: ty2, ..., ~labeln: tyn` +Expressions: `~label1: ty1, ~label2: ty2, ... , ~labeln: tyn` -Patterns: `~label: ty1, ~label: ty2,..., ~labeln: tyn` +Patterns: `~label: ty1, ~label: ty2, ... , ~labeln: tyn` -This was very similar to the final dot notation used. However, the dot opearator was chosen over the tilda operator since the tilda key is harder to acces than the dot on a keyboard, and the dot operator was already associated with projection so it made sense to associate it with label annotations as well. +This was very similar to the final dot notation used. However, the dot operator was chosen over the tilda operator. This is because the tilda key is harder to acces than the dot on a keyboard, and the dot operator was already associated with projection. It made more sense to associate the dot operator with label annotations rather than the tilda operator. ### Space Separator with No Label Annotations -Types: `label1 ty1, label2 ty2, ..., labeln tyn` +Types: `label1 ty1, label2 ty2, ... , labeln tyn` -Expressions: `label1 e1, label2: e2, ..., labeln: en` +Expressions: `label1 e1, label2: e2, ... , labeln: en` Patterns: `label1 p1, label2 p2, ..., labeln pn` -This suggestion reduces the amount of additional operators needed for labled products. However, there is no way to tell distinction between undefined function variable application and labeled expression, so this syntax would not work. +This suggestion reduces the number of additional operators needed for labled products. However, there is no way to tell distinction between undefined function variable application and labeled expression, so this syntax would not work. ### Colon Operator Types: `label1: ty1, label2: ty2, ..., labeln: tyn` @@ -234,7 +246,7 @@ Expressions: `label1: e1, label2: e2, ..., labeln: en` Patterns: `label1: p1, label2: p2, ..., labeln: pn` -This syntax imitates many other languages, which use a colon operator to separate labels and values in record types. However, this creates onfusion between labeled pair type annotation and type annotations as they both would use the colon operator. For this reason, this option was not used. +This syntax imitates many other languages, which use a colon operator to separate labels and values in record types. However, this creates onfusion between labeled pair type annotation and type annotations as they both would use the colon operator. For this reason, this option was not used. ### Colons and Braces Types: `{label1: ty1, label2:ty2, ..., labeln:tyn}` @@ -243,4 +255,4 @@ Expressions: `{label1: e1, label2:e2, ..., labeln:e2}` Patterns: `{label1: p1, label2: p2, ..., labeln: pn}` -This syntax is more typical for a record, and may create confusion about labeled tuples as a value and records as a type definition. In addition, adding logic for braces within Hazel would increase implementation complexity a great deal. \ No newline at end of file +This syntax is more typical for a record. This may create confusion about labeled tuples using positional arguments and records typically being unordered. In addition, adding logic for braces within Hazel would increase implementation complexity a great deal compared to the final dot notation discussed in this proposal. \ No newline at end of file From 091e19ba74db0bd9e47a1a3271c33b62b7786f58 Mon Sep 17 00:00:00 2001 From: ecdeuts Date: Sun, 24 May 2020 23:58:09 -0400 Subject: [PATCH 10/12] edits from pr except syn/ana and draft of action semantics section --- 1-labeled-tuples/1-labeled-tuples.md | 87 ++++++++++++++-------------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index ca056a8..b126df7 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -6,8 +6,14 @@ Labeled products are a type of value. They are similar to products, but some or Adding labeled products helps with readability of products, so more complex products can be easily used within Hazel. Remembering the positions of values in along product may be difficult, so labels allow for easy access of values in a product. The labeled products serve a similar purpose as records in other languages. Currently only unlabeled tuples are supported in Hazel, and elements can only be accessed positionally using pattern matching (via let or case). + +# Label Syntax +Say what the regex for labels are +Say it's the same syntax for variable identifyers (ie no spaces) +Say that the dot is used + # Labeled Product Types -Syntax: `.label1 ty1, .label2 ty2, ..., .labeln tyn` + Files to Edit: UHTyp.re @@ -27,7 +33,7 @@ Space will be left associateive and have the highest precedence. ``` type operand = ... - | Label(Label.t); + | Label(Label.t); //.label ``` @@ -36,11 +42,11 @@ For example, the labeled product type `(.x Num, Num, .y Num)` is allowed. Singleton label products are supported. For example, `.x Num` is supported. -### Type Equivalence +## Type Equivalence A labeled product may still be used with positional arguments, so the type equivalence considers the order of the labels with equlivalence. For example, `(.x Num, .y Num, .z Num) != (.z Num, .y Num, .x Num)` because the order of the labels is different. -### Type Syntax Errors +## Type Syntax Errors Files to Edit: CursorInfo.re * A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error. @@ -59,24 +65,18 @@ Files to Edit: CursorInfo.re * Error Cursor appears on second and third use of `.label1`
* Expecting a Unique Label Got a Duplicate Label -# Labeled Tuple Expressions +# Expressions -Syntax: `.label1 e1, .label2 e2, ..., .labeln en` +Both label tuple expressions and projection expressions must be added to Hazel to implement labeled tuples. +## Labeled Tuples Files to Edit: UHExp.re -To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels and projections. -``` -type operator = - ... - | Dot; -``` -The Dot operator will be left associative and have highest precedence. +To add labeled tuples, the operand type must be expanded to include labels. ``` operand = ... - | Label(Label.t) - | Prj(UHExp.t, Label.t) + | Label(Label.t) //.label ``` @@ -95,39 +95,32 @@ TODO: what are the type synthesis and type analysis rules for the labeled tuple ### Punning Some languages, such as Reason, have record punning. This is where a record's labels can be implied when it is declared using variables. For example, `{x, y, z} => {x: x, y: y, z: z}` is true. Similar punning fuctionality could be implemented in Hazel. For example, if this punning was implemented `(x, y, z) => (x: x, y: y, z: z)` would hold true. However, this creates a question of if every tuple created with variables should be a labeled tuple. Given this additional complexity and added development costs, I believe that labeled tuple punning should be considered out of scope for labeled tuples. -### Projection Expressions - -Syntax: `e.label` +## Projection Files to Edit: UHExp.re Labels can be used to access elements of a pair through projection expressions. To add projection, the operand type must be extended to include projection. - ``` operand = ... - | Prj(UHExp.t, Label.t) + | Prj(UHExp.t, Label.t) // e.label ``` `e.label` will be the new expression form. `e.label` expects `e` to synthesize to a labeled tuple type and `label` to match one of the labels within `e`. `e.label` will return the value that has the label `label`. -#### Backspace -You can press backspace on `e |.label` and get to `e.label` -You can press space on `e|.label` and get to `e .label` - -### Type Sythesis and Type Analysis Rules for Labeled Product Expressions -#### Synthesis +## Type Sythesis and Type Analysis Rules for Labeled Product Expressions +### Synthesis ![Synthesis Rule for Labeled Product](syn_2.png) ![Synthesis Rule for Projection](syn_1.png) -#### Analysis +### Analysis ![Analysis Rule Single](ana_1.png) ![Analysis Rule Tuple](ana_2.png) -### Expression Syntax Errors +## Expression Syntax Errors Files to Edit: CursorInfo.re + A label must be followed by a valid expression and comma operator, not another label. For example, `.label1 .label2 e` produces an error. @@ -140,7 +133,7 @@ Files to Edit: CursorInfo.re + Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 e1 .label2` produces an error. + Error cursor appears on space operator
- + Message: Expecting ? Got an Unexpected Label + + Message: Expecting Comma or Other Type Operator Got an Unexpected Label + Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, `.label1 1, .label1 3, .label2 4, .label1 True` will produce an error. + Error cursor appears on second and third use of `.label1`
@@ -155,17 +148,12 @@ Syntax: `.label1 p1, .label2 p2, ..., .labeln pn` Files to Edit: UHPat.re -To add labeled tuples, the operator type must be expanded to include the dot operator and operand type must be expanded to include labels. -``` -type operator = -... - | Dot; -``` -The Dot operator will be left associative and have highest precedence. +To add labeled tuples, the operand type must be expanded to include labels. + ``` and operand = ... - | Label(LabelErrStatus.t, string) + | Label(LabelErrStatus.t, string) .label ``` Partially labeled product patterns are allowed, and labels and non-labeled positions can be interleaved. @@ -173,7 +161,7 @@ For example, the labeled product type `(.x p1, p2, .y p3)` is allowed. Singleton label products are supported. For example, `.x p1` is supported. -### Synthesis and Analysis +## Synthesis and Analysis An unlabeled product pattern can match to a labeled product expression, allowing you to ommit labels. For example, `(.x 1, .y 2, .z 3)` can match on the pattern `(a, b, c)`. This operation happens positionally. @@ -181,7 +169,7 @@ A labeled tuple pattern must match the label names and the order of a labeled tu A partially labeled pattern can match with a fully labled expression as long as the labels that do exist match. For example, `(.x 1, .y 2, .z 3)` will match on `(.x p1, p2, .z p3)` -### Punning +## Punning Punning may be useful for labeled tuple patterns, where the label can be used to access the element rather than adding an aditional variable. For example, with punning this code snippit: ``` @@ -200,7 +188,7 @@ f(.x 1, .y 2) This would be a great quality of life improvement to patterns with labeled tuples, and will be attempeted with the initial implementation of labeled tuples. It will be considered lower priority, since it is not required for labeled tuples patterns to function at a basic level. -### Pattern Syntax Errors +## Pattern Syntax Errors Files to Edit: CursorInfo.re + Multiple labels must be followed by the comma operator, not another label. For example, `.label1 .label2` produces an error.
@@ -209,19 +197,28 @@ Files to Edit: CursorInfo.re + Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 p1 .label2 p2` produces an error.
+ Error cursor appears on space operator
- + Message: Expecting ? Got an Unexpected Label + + Message: Expecting Comma or other Expression Operator Got an Unexpected Label + Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, `.label1 p1, .label1 p2, .label2 p3, .label1 p4` produces an error. + Error cursor appears on second and third use of `.label1`
+ Message: Expecting a Unique Label Got a Duplicate Label +# Action Semantics +## Create +Adding a dot by itself should imply that a label is being created. `.` will get to `.(Label Hole)` + +## Delete +You can press backspace on `e |.label` and get to `e.label` + +You can press space on `e|.label` and get to `e .label` + # What About Records? Records in other languages are very similar to the labeled tuples in this propoasal. Records are typically a data structure that bundles data together with labels and values, and the values are accessed using projection with the labels. The values are unordered in a record, while the values are ordered in a labeled tuple. A labeled tuple is able to perform the same functions as a record, while adding additional functionality by ordering data. If labeled tuples are sucessfully added to Hazel, then records will be redundant in Hazel. # Appendix: Other Ideas While creating this proposal, I considered many other ideas for Hazel labels. These ideas are detailed below. -### Reason Like ~label Annotations +## Reason Like ~label Annotations Types: `~label1: ty1, ~label2: ty2, ... , ~labeln: tyn` Expressions: `~label1: ty1, ~label2: ty2, ... , ~labeln: tyn` @@ -230,7 +227,7 @@ Patterns: `~label: ty1, ~label: ty2, ... , ~labeln: tyn` This was very similar to the final dot notation used. However, the dot operator was chosen over the tilda operator. This is because the tilda key is harder to acces than the dot on a keyboard, and the dot operator was already associated with projection. It made more sense to associate the dot operator with label annotations rather than the tilda operator. -### Space Separator with No Label Annotations +## Space Separator with No Label Annotations Types: `label1 ty1, label2 ty2, ... , labeln tyn` Expressions: `label1 e1, label2: e2, ... , labeln: en` @@ -239,7 +236,7 @@ Patterns: `label1 p1, label2 p2, ..., labeln pn` This suggestion reduces the number of additional operators needed for labled products. However, there is no way to tell distinction between undefined function variable application and labeled expression, so this syntax would not work. -### Colon Operator +## Colon Operator Types: `label1: ty1, label2: ty2, ..., labeln: tyn` Expressions: `label1: e1, label2: e2, ..., labeln: en` @@ -248,7 +245,7 @@ Patterns: `label1: p1, label2: p2, ..., labeln: pn` This syntax imitates many other languages, which use a colon operator to separate labels and values in record types. However, this creates onfusion between labeled pair type annotation and type annotations as they both would use the colon operator. For this reason, this option was not used. -### Colons and Braces +## Colons and Braces Types: `{label1: ty1, label2:ty2, ..., labeln:tyn}` Expressions: `{label1: e1, label2:e2, ..., labeln:e2}` From 536264f3f237f5a65fcf9f7c563ca43b2af620e9 Mon Sep 17 00:00:00 2001 From: ecdeuts Date: Mon, 13 Jul 2020 15:51:57 -0400 Subject: [PATCH 11/12] fixed formatting error with bulleted lists --- 1-labeled-tuples/1-labeled-tuples.md | 55 ++++++++++++--------------- 1-labeled-tuples/rules.png | Bin 0 -> 78248 bytes 2 files changed, 25 insertions(+), 30 deletions(-) create mode 100644 1-labeled-tuples/rules.png diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index b126df7..730d848 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -50,20 +50,20 @@ A labeled product may still be used with positional arguments, so the type equiv Files to Edit: CursorInfo.re * A label must be followed by a valid type and comma operator, not another label. For example, `.label1 .label2 ty` produces an error. - * Error Cursor appears on `.label2` - * Expecting a Type Got a Label + * Error Cursor appears on `.label2` + * Expecting a Type Got a Label * A label cannot exist by itself; it is given meaning by having a type follow it. For example, `.label1 ` by itself produces an error. - * Error Cursor appears on `.label1` - * Message: Expecting a Type Got a Label + * Error Cursor appears on `.label1` + * Message: Expecting a Type Got a Label * Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 ty .label2` produces an error. - * Error cursor appears on space operator - * Message: Expecting ? Got an Unexpected Label + * Error cursor appears on space operator + * Message: Expecting ? Got an Unexpected Label * Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. FOr example, the type `.label1 Num, .label1 Num, .label2 Num, .label1 Bool` will have errors on the second use of `.label1 Num` and `.label1 Bool` - * Error Cursor appears on second and third use of `.label1`
- * Expecting a Unique Label Got a Duplicate Label + * Error Cursor appears on second and third use of `.label1`
+ * Message: Expecting a Unique Label Got a Duplicate Label # Expressions @@ -112,36 +112,31 @@ operand = ## Type Sythesis and Type Analysis Rules for Labeled Product Expressions ### Synthesis -![Synthesis Rule for Labeled Product](syn_2.png) +![Synthesis Rule for Labeled Product](rules.png) -![Synthesis Rule for Projection](syn_1.png) - -### Analysis -![Analysis Rule Single](ana_1.png) -![Analysis Rule Tuple](ana_2.png) ## Expression Syntax Errors Files to Edit: CursorInfo.re + A label must be followed by a valid expression and comma operator, not another label. For example, `.label1 .label2 e` produces an error. - + Proposed Error Message: Error Cursor appears on `.label2` - + Message: Expecting an Expression Got a Label + + Proposed Error Message: Error Cursor appears on `.label2` + + Message: Expecting an Expression Got a Label + A label cannot exist by itself; it is given meaning by having an expression follow it. For example, `.label1 ` by itself produces an error. - + Error Cursor appears on `.label1`
- + Message: Expecting an Expression Got a Label + + Error Cursor appears on `.label1`
+ + Message: Expecting an Expression Got a Label + Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 e1 .label2` produces an error. - + Error cursor appears on space operator
- + Message: Expecting Comma or Other Type Operator Got an Unexpected Label + + Error cursor appears on space operator
+ + Message: Expecting Comma or Other Type Operator Got an Unexpected Label + Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, `.label1 1, .label1 3, .label2 4, .label1 True` will produce an error. - + Error cursor appears on second and third use of `.label1`
- + Message: Expecting a Unique Label Got a Duplicate Label + + Error cursor appears on second and third use of `.label1`
+ + Message: Expecting a Unique Label Got a Duplicate Label + Using the dot operator as a binary operator on a type that is not a labeled tuple will produce an error. This error will appear on the expression to the left of the dot operator that is not a labeled product. For example, the expression `1.label1` will produce an error - + Error cursor appears on`1` - + Message: Expecting a Labeled Product Got a Num + + Error cursor appears on`1` + + Message: Expecting a Labeled Product Got a Num # Labeled Tuple Patterns Syntax: `.label1 p1, .label2 p2, ..., .labeln pn` @@ -192,16 +187,16 @@ This would be a great quality of life improvement to patterns with labeled tuple Files to Edit: CursorInfo.re + Multiple labels must be followed by the comma operator, not another label. For example, `.label1 .label2` produces an error.
- + Error cursor appears on `.label2` - + Message: Expecting a Pattern Got a Label + + Error cursor appears on `.label2` + + Message: Expecting a Pattern Got a Label + Elements in the tuples need to be separated by commas, if they are not then this produces an error. For example, `.label1 p1 .label2 p2` produces an error.
- + Error cursor appears on space operator
- + Message: Expecting Comma or other Expression Operator Got an Unexpected Label + + Error cursor appears on space operator
+ + Message: Expecting Comma or other Expression Operator Got an Unexpected Label + Duplicate labels within a tuple are not valid, so they produce an error. The error will appear on the subsequent duplicate uses, not on the type as a whole. For example, `.label1 p1, .label1 p2, .label2 p3, .label1 p4` produces an error. - + Error cursor appears on second and third use of `.label1`
- + Message: Expecting a Unique Label Got a Duplicate Label + + Error cursor appears on second and third use of `.label1`
+ + Message: Expecting a Unique Label Got a Duplicate Label # Action Semantics ## Create diff --git a/1-labeled-tuples/rules.png b/1-labeled-tuples/rules.png new file mode 100644 index 0000000000000000000000000000000000000000..c55e2a4040696e7747a28b33b1d15f54ce2e9369 GIT binary patch literal 78248 zcmeFZcTm%7w>BIVWwUKta4VpIiU=r8klw6-Q~{+(mnJ2EAiXIf=oUexiBvaIq)UsT zswgcKL3$`6QbUN;2qEyUJ3h~Ip7)z?=6h$(neY7Z9%lByj>#{--(A+a)^%O$et1P& zb@%U_zhf|%-Ivua>R~Y3!!ej0>c8!PSMD7cW`|!}JoHr0V+z_1Ps9H(*`L!ohrzsw z+PQAE9sZxiP0iQ?gE>Bh{@W5_z5Or-vzc-E;<>9n=CecOT+{Jt<&7qaZ}&~^y#-xS{98q}>ax zL%%Ux#}A`%z)T(azv~iREVI4)5{p^!H4J4$!%Uwr?iFgltkJr8O^rbI}vM|2s@i4B>z4=oE+#Pxg zEi49B-M&5Km-46{9w>AAk9V-oMC&LC+8)qbvyuw@IU1g!IGN<3F3+R1@pG)R;Cfk3 z>AgWeQoe1l!b+cYt0c_JBXnW*nbB|_5pqVn`SpSRg*8%P{7T495dm_5&t$Tu@`tG-3XCEp_SZEYHDf;=vu44#s*(9lsqo_E@@k{dHE#^?}tN zvnB0uD=iZ3LRca^_2)`*InggQaK+elbz!_(Ut2Z->xqZG}t)} zEdo991==hcyyRDB_h^MY0ZGav>I3)mh=ns@G<6Gt4S(Pe+6m_;Py^ zXI3(VJ{}?8Su6dbeF_^p`Q+@|NY3Hf;LSd9i6OVT-Q#PzSYmm;f(Xs#iD@d)qxSyS zPX{f8+E3F8l_qCfnZm}`$=7;x>ukVN3lI02GU0++rS7QEdEI*tD((R60BKIoG{gX!r88{s7d+jRDr-EePabz8|#&+Zg{*@^WBTHv~Q0@=eT6t z(llA5OY-+B{j~IGFRY>t`)6pK4eT+tk6m>fsRR_Vo6E(+6cUcl2Wj2qM& zn2lyC#Nv}k>BFME-B-MFzFg(gto`v}Cn4a&qQc1G#Ri_>DsLF_IMNoF6b&>fSDk(o zm{(Vn(l;i9H?pXoFYJv?`}rzb`(!WQS*@QhI6qW+Q$(z8gp8?O8RQA8_h?r%9Ed$- z80RJDD3)|ba&*PB*Q{55G?cA*DLQri)!^jnWU45ZND!?x9k413Eg9sz-EKGisLZK% zr3V(`1Su#{l;tN|rt3iIYo@QBSE)L|YhOBh#36{i`-YbI4!^}#X$|?j;UCG~!?IG% zE9p^6C$TDfH+zHWhLq{7RFQM`&cjvs()qbcij;@NYhK%S<<0d@ZPl5r_MxOWVUyunomYkM>y8EjL z6_v--s0dg&Q5vLI0T@itPl#Q2?mFHiTHNz~!dYvYw!9h3qM$GJt@%`;a{;~Csj%8$z-o&pmvK_j?F!bl6Gd9TRbA

+whszItt~ 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 Rdxri;{hZEkd1owd|1Sc+ Date: Wed, 15 Jul 2020 10:37:14 -0400 Subject: [PATCH 12/12] Added label syntax section --- 1-labeled-tuples/1-labeled-tuples.md | 38 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/1-labeled-tuples/1-labeled-tuples.md b/1-labeled-tuples/1-labeled-tuples.md index 730d848..02eac2e 100644 --- a/1-labeled-tuples/1-labeled-tuples.md +++ b/1-labeled-tuples/1-labeled-tuples.md @@ -1,23 +1,23 @@ # Introduction - -Labeled products are a type of value. They are similar to products, but some or all elements have a label. The label is used with projection. This allows elements within the product to be accessed either positionally or by the label. - + +Labeled products are a type of value. They are similar to products, but some or all elements have a label. The label is used with projection, which allows elements within the product to be accessed either positionally or by the label. + Adding labeled products helps with readability of products, so more complex products can be easily used within Hazel. Remembering the positions of values in along product may be difficult, so labels allow for easy access of values in a product. The labeled products serve a similar purpose as records in other languages. - + Currently only unlabeled tuples are supported in Hazel, and elements can only be accessed positionally using pattern matching (via let or case). # Label Syntax -Say what the regex for labels are -Say it's the same syntax for variable identifyers (ie no spaces) -Say that the dot is used +Label syntax must match the following regular expression: ```\.[a-zA-Z]\w*``` + +A label must start with the `.` character, followed by a letter, and then any number of alphanumeric charaters or underscores. # Labeled Product Types Files to Edit: UHTyp.re - - + + @@ -36,7 +36,7 @@ type operand = | Label(Label.t); //.label ``` - + Partially labeled product types are allowed, and labels and non-labeled positions can be interleaved. For example, the labeled product type `(.x Num, Num, .y Num)` is allowed. @@ -66,7 +66,7 @@ Files to Edit: CursorInfo.re * Message: Expecting a Unique Label Got a Duplicate Label # Expressions - + Both label tuple expressions and projection expressions must be added to Hazel to implement labeled tuples. ## Labeled Tuples @@ -78,20 +78,20 @@ operand = ... | Label(Label.t) //.label ``` - + Partially labeled product expressions are allowed, and labels and non-labeled positions can be interleaved. For example, the labeled product expression `(.x 2, 3, .y True)` is allowed. Singleton label product expressions are supported. For example, `.x 2` is supported. - + An unlabeled product expression can analyze to a labeled product expression, allowing you to omit labels. For example, `(1, 2, 3) <= (.x Num, .y Num, .z Num)` is valid and each value in `(1,2,3)`. This operation happens positionally, and does not assign labels based on variable name if variables are used. For example, `(y, x, z) <= (.x Num, .y Num, .z Num)` is valid. +"Record punning" in Reason: `{x, y, z} => {x: x, y: y, z: z}` -- is there anything analogous that we can do? Does this interact with positional values? `(y, x, z) <= (.x Num, .y Num, .z Num)` does that operate positionally or via punning? +partially labeled values, where some of the arguments are in order: `(1, 2, .z 3) <= (.x Num, .y Num, .z Num)`. what about interleaving vs. requiring all the explicit labels at the end ala Python? +what are the type synthesis and type analysis rules for the labeled tuple expressions --> ### Punning Some languages, such as Reason, have record punning. This is where a record's labels can be implied when it is declared using variables. For example, `{x, y, z} => {x: x, y: y, z: z}` is true. Similar punning fuctionality could be implemented in Hazel. For example, if this punning was implemented `(x, y, z) => (x: x, y: y, z: z)` would hold true. However, this creates a question of if every tuple created with variables should be a labeled tuple. Given this additional complexity and added development costs, I believe that labeled tuple punning should be considered out of scope for labeled tuples. @@ -112,7 +112,7 @@ operand = ## Type Sythesis and Type Analysis Rules for Labeled Product Expressions ### Synthesis -![Synthesis Rule for Labeled Product](rules.png) +![Synthesis and Analysis Rules for Labeled Products](rules.png) ## Expression Syntax Errors @@ -150,14 +150,14 @@ and operand = ... | Label(LabelErrStatus.t, string) .label ``` - + Partially labeled product patterns are allowed, and labels and non-labeled positions can be interleaved. For example, the labeled product type `(.x p1, p2, .y p3)` is allowed. Singleton label products are supported. For example, `.x p1` is supported. ## Synthesis and Analysis - + An unlabeled product pattern can match to a labeled product expression, allowing you to ommit labels. For example, `(.x 1, .y 2, .z 3)` can match on the pattern `(a, b, c)`. This operation happens positionally. A labeled tuple pattern must match the label names and the order of a labeled tuple expression for a pattern match. For example, `(.x a, .y b, .z c)` will match with `(.x 1, .y 2, .z 3)` but will not match with `(.y 1, .z 2, .x 3)` because the order does not match.