<div dir="ltr"><div dir="ltr">On Tue, Jun 29, 2021 at 7:05 AM Anthony Clayden <<a href="mailto:anthony.d.clayden@gmail.com">anthony.d.clayden@gmail.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><br></div><div class="gmail_quote"><div>Because almost always you need to put parens round -- certainly in a pattern match.</div><div><br></div></div></div></blockquote><div><br></div><div>This is an interesting point, and for the sake of having an unambiguous parser, I don't think this requirement is needed: The arity of all constructors is known, all constructors must have all of its arguments (no currying in patterns), so Polish notation should suffice and parentheses could be optional (an implementer would need to delay parsing of anything to the lhs of an <- or = until all constructors are known). With infix operators (`a:b:c` should not be parsed as `(a:b):c`) we simply take fixity into. To a certain extent Haskell already does this, the following works:</div><div><br></div><div>





<p class="gmail-p1" style="margin:0px;font-variant-numeric:normal;font-variant-east-asian:normal;font-stretch:normal;font-size:14px;line-height:normal;font-family:"Lucida Console";color:rgb(59,35,34);background-color:rgb(215,211,183)"><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures">infixr 3 `member`</span></p>
<p class="gmail-p1" style="margin:0px;font-variant-numeric:normal;font-variant-east-asian:normal;font-stretch:normal;font-size:14px;line-height:normal;font-family:"Lucida Console";color:rgb(59,35,34);background-color:rgb(215,211,183)"><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures">a `member` []                  = False</span></p>
<p class="gmail-p1" style="margin:0px;font-variant-numeric:normal;font-variant-east-asian:normal;font-stretch:normal;font-size:14px;line-height:normal;font-family:"Lucida Console";color:rgb(59,35,34);background-color:rgb(215,211,183)"><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures">a `member` b : bs | b==a       = True</span></p>
<p class="gmail-p1" style="margin:0px;font-variant-numeric:normal;font-variant-east-asian:normal;font-stretch:normal;font-size:14px;line-height:normal;font-family:"Lucida Console";color:rgb(59,35,34);background-color:rgb(215,211,183)"><span class="gmail-s1" style="font-variant-ligatures:no-common-ligatures"><span class="gmail-Apple-converted-space">                  </span>| otherwise  = a `member` bs</span></p></div><div><br></div><div>To make this work in general, any function symbols on the lhs of an = (and their respective function application) should have the lowest precedence, and constructor 'application' through spaces would seem to go in the opposite direction of what is common. Following this convention, we could have this amusing looking definition in the Prelude:</div><div>x:xs++ys = x:xs++ys</div><div>On the lhs, since ++ is not a constructor, it is the symbol that is being defined and therefore of lowest precedence, so the lhs would read (x:xs)++ys. On the rhs, (:) and (++) are infixr 5, so the rhs reads as x:(xs++ys).</div><div>Just to be clear: none of this is a proposal, I would not be in favor of this as I prefer consistency.</div><div><br></div><div>As to the original question: I see no technical issues in allowing something like `[ x, y || ys]` as syntax for `(x:y:ys)`, or using any new symbol in place of ||. As others have pointed out, we cannot have all three of:</div><div>- `[ expr ]` stands for singleton list elements (as currently the case)</div><div>- keep the current meaning of `x : xs`</div><div>- let `[ x : xs ]` be 'shorthand' for `x:xs`</div><div>From a Prolog perspective, dropping `x : xs` may seem the way to go (arguments like: "in many patterns we need parentheses anyways" seem to agree with this view), but Haskell code has `foo x y` instead of `foo(x,y)`, and infix syntax follows the same principle: outer parentheses are optional. Prolog follows the same principle for +, *, -, =, etc, just not for relations.<br></div><div><br></div><div>Would I be violently against even something mild like the introduction of `[ x,y || ys ]`? Not violently so but definitely fiercely, unless this is tucked away behind a flag. I see it as pointless, wouldn't use it, and I don't care to explain it to my students (or at least those who don't know Prolog) either, and it would reduce 3rd party code readability because there would now be two ways of writing the same thing, neither of which is entirely obvious. In a new / different language I'd love to see all these weird ideas tried out. Sometimes odd conventions (such as writing `foo x y` instead of `foo(x,y)`) grow on me and I start to like them. A good place to start might be to add outer parentheses to your language to distinguish `[x : xs]` from `[(x : xs)]`, forbidding `x : xs`. This would be LISP with infix notations and static typing... that actually sounds like it could be nice.<br></div><div><br></div><div>While we're on the topic of changing list syntax, some more ideas that might make sense (but are not a proposal!!):</div><div> `[ x,y | binders ]`  as syntax for:  `concat [ [x,y] | binders ]`<br></div><div> `[ x ..< y ]` as syntax for `FromEnumToExclusive x y` (i.e. `if x==y then [] else [x..pred y]` by default), Isabelle/HOL has this.</div><div> A keyword `get` in addition to `let` s.t. `[x | get Just x = y]` is syntax for `[x | Just x <- [y]]` (using let produces a pattern match failure if y=Nothing).</div><div> While we're at it: `do {get Just x = ys; continuation}` as syntax for `do {Just x <- return ys; continuation}`.</div><div> `[ x | xs <- as; x <- xs]` as syntax for: `[x | xs <- as, x <- xs]` (the ; would have the binders behave like `do-syntax`).</div><div> While we're at it: `[ expr | binders]` as syntax for: `do {binders;return expr} :: (Listlike f => f b)` with `default Listlike ([])`.</div><div> Finally, `do {(binders1 | binders2) ; continuation}` could be syntax for: `Data.Zip.zipWith (\x y -> continuation) (do binders1;return x) (do binders2; return y)` (as inspired by parallel list comprehensions).</div><div><br></div><div>It's fun to think about these things, but each of these ideas comes with syntactic change and therefore yet another language construct to learn. Since syntax cannot be found on <a href="https://hoogle.haskell.org/?hoogle=..">hoogle</a> and even <a href="http://what does .. mean in haskell">google</a>, all of these things generally increase the burden to the reader of your code, which is why none of this is a proposal.</div><div><br></div><div>Best,</div><div>Sebastiaan</div></div></div>