<div dir="ltr"><div class="gmail_default" style="font-family:monospace,monospace">I believe I already said that an OR-pattern is allowed anywhere a pattern is allowed.</div><div class="gmail_default" style="font-family:monospace,monospace">Further, an alternative of an OR-pattern may bind variables if and only if</div><div class="gmail_default" style="font-family:monospace,monospace">every alternative of the OR-pattern binds the same variables (ignoring wild cards).</div><div class="gmail_default" style="font-family:monospace,monospace">(Not entirely unlike Erlang 'case'.)</div><div class="gmail_default" style="font-family:monospace,monospace">It's the same in F#.  Here's an example from the manual.</div><div class="gmail_default" style="font-family:monospace,monospace"><span class="m_-8089605046955528917gmail-hljs-keyword" style="box-sizing:inherit;color:rgb(1,1,253);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap">let</span><span style="color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap;background-color:rgb(250,250,250)"> detectZeroOR point =
    </span><span class="m_-8089605046955528917gmail-hljs-keyword" style="box-sizing:inherit;color:rgb(1,1,253);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap">match</span><span style="color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap;background-color:rgb(250,250,250)"> point </span><span class="m_-8089605046955528917gmail-hljs-keyword" style="box-sizing:inherit;color:rgb(1,1,253);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap">with</span><span style="color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap;background-color:rgb(250,250,250)">
    | (</span><span class="m_-8089605046955528917gmail-hljs-number" style="box-sizing:inherit;color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap">0</span><span style="color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap;background-color:rgb(250,250,250)">, </span><span class="m_-8089605046955528917gmail-hljs-number" style="box-sizing:inherit;color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap">0</span><span style="color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap;background-color:rgb(250,250,250)">) | (</span><span class="m_-8089605046955528917gmail-hljs-number" style="box-sizing:inherit;color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap">0</span><span style="color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap;background-color:rgb(250,250,250)">, _) | (_, </span><span class="m_-8089605046955528917gmail-hljs-number" style="box-sizing:inherit;color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap">0</span><span style="color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap;background-color:rgb(250,250,250)">) -> printfn </span><span class="m_-8089605046955528917gmail-hljs-string" style="box-sizing:inherit;color:rgb(163,21,21);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap">"Zero found."</span><span style="color:rgb(0,0,0);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap;background-color:rgb(250,250,250)">
    | _ -> printfn </span><span class="m_-8089605046955528917gmail-hljs-string" style="box-sizing:inherit;color:rgb(163,21,21);font-family:Consolas,Menlo,Monaco,"Lucida Console","Liberation Mono","DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace,sans-serif;font-size:14px;white-space:pre-wrap">"Both nonzero."</span>  <br></div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">So that is at least three functional languages that currently support</div><div class="gmail_default" style="font-family:monospace,monospace">OR-patterns: Caml, F#, and SML (both SML/NJ and MLton).</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">However, it seems likely that this fills a much-needed gap.</div><div class="gmail_default" style="font-family:monospace,monospace">Complex patterns are probably wrong.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 28 Mar 2019 at 01:29, Jesper Louis Andersen <<a href="mailto:jesper.louis.andersen@gmail.com" target="_blank">jesper.louis.andersen@gmail.com</a>> wrote:<br></div><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"><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">On Wed, Mar 27, 2019 at 2:17 AM José Valim <<a href="mailto:jose.valim@plataformatec.com.br" target="_blank">jose.valim@plataformatec.com.br</a>> wrote:<br></div></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"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">> <span style="font-family:monospace,monospace">Everybody seems to be chasing after how to express "X in [...]" as a guard</span></div><div style="font-family:monospace,monospace">without responding to the suggestion of copying SML/NJ's "or patterns"</div><div dir="ltr"><br></div><div>What are the restrictions for OR patterns?</div><div>Can OR patterns be allowed anywhere in a pattern (i.e. arbitrarily nested) or are they allowed only at the root?</div><div>Can we bind variables inside OR patterns?</div><div><br></div></div></div></div></div></div></div></blockquote><div><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">I'll use Ocaml as the language for this, since it has the same pattern as SML/NJ, and I happen to have Ocaml installed, but not SML/NJ.</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">In erlang we write:</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">case Exp of</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">  P1 -> E1;</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">  P2 -> E2;</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">  P3 -> E3</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">end</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">In Ocaml, we would write</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">match Exp With</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">| P1 -> E1</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">| P2 -> E2</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">| P3 -> E3</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">Note that we prefix each pattern by '|' rather than separate them with ';' as in Erlang. The semantics are otherwise the same at least up to a very high level of equivalence. Now suppose, we have a case where we want to write</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">match Exp with</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">| P1 -> E</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">| P2 -> E</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">| P3 -> E3</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">That is, both patterns P1 and P2 runs the same function body E. In this case, Ocaml allows us to avoid the repetition, the so-called OR-pattern:</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">match Exp with</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">| P1 | P2 -> E</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">| P3 -> E3</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">What are the rules? Any use of a variable 'x' in E must be bound in the scope and must have the same type. That is, if P1 binds 'x : t' i.e., with type t, then P2 must also bind 'x : t'. In principle, we could allow it if the scope/context has 'x : t' and it isn't bound in P2, but this is currently rejected by the language, probably on the grounds of being prone to error.</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">The compiler has a relatively easy rewrite to make:</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">let body_E x = E in</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">  match Exp with</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">  | P1 x -> body_E x</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">  | P2 x -> body_E x</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">  ...</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">more or less (caveat: capture! body_E must be be passed parameters appropriately if it uses them from the context. Further optimizations might then lift them). Extract the common body into a local function and apply that function. Further optimizations are often able to remove 'body_E' from the generated code. Since we are in ML-land with Standard ML and Ocaml, the Mlton compiler has a contification optimization which will fuse the body_E continutation appropriately. This can then uncover further optimizations down the road.<br></div><br></div></div>
</blockquote></div>