<div dir="ltr">By parametrizing over a type-level record, you can encode the names of matched subgroups in the type of the regular expression. The interface probably looks something like:<div><br></div><div><span style="font-family:monospace,monospace">(* Abstract type of uncompiled regular expressions. *)</span><br></div><div><font face="monospace, monospace">con t :: {Unit} (* names of captured subgroups *) -> Type</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">val literal :</font></div><div><font face="monospace, monospace">    string -> t []</font></div><div><font face="monospace, monospace">val any : t []</font></div><div><font face="monospace, monospace">val concat : r1 ::: {Unit} -> r2 ::: {Unit} -> [r1 ~ r2] </font><span style="font-family:monospace,monospace">=></span></div><div><span style="font-family:monospace,monospace">    t r1 -> t r2 -> t (r1 ++ r2)</span></div><font face="monospace, monospace">val star : r ::: {Unit} </font><span style="font-family:monospace,monospace">-></span><div><span style="font-family:monospace,monospace">    t r -> t r</span><div><div><font face="monospace, monospace">val alt : r ::: {Unit} -> s1 ::: {Unit} -> s2 ::: {Unit} -> [r ~ s1] => [r ~ s2] => [s1 ~ s2] </font><span style="font-family:monospace,monospace">=></span></div><div><span style="font-family:monospace,monospace">    t (r ++ s1) -> t (r ++ s2) -> t (r ++ s1 ++ s2)</span></div><div><font face="monospace, monospace">val capture : r ::: {Unit} -></font></div><div><font face="monospace, monospace">    nm :: Name -> [r ~ [nm]] => t r -> t (r ++ [nm])</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">(* Abstract type of compiled regular expressions *)</font></div><div><font face="monospace, monospace">con compiled :: {Unit} -> Type</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">val compile : r ::: {Unit} -></font></div><div><font face="monospace, monospace">    t r -> compiled r</font></div><div><br></div></div></div><div>Obviously this probably won't exactly work. For instance, if the underlying library requires explicit names for captured groups, you'll need something more like</div><div><br></div><div><div><font face="monospace, monospace">val capture : r ::: {Unit} -> </font><span style="font-family:monospace,monospace">nm :: Name -> [r ~ [nm]] =></span></div><div><span style="font-family:monospace,monospace">    {nm : string} -> t r -> t (r ++ [nm])</span></div></div><div class="gmail_extra"><br></div><div class="gmail_extra">because there's no way to extract a string from a type-level Name. In fact, this way has another benefit: the internal representation of the type can just be a string! All the tracking of subgroups can happen at the type level. You may not even need compile.</div><div class="gmail_extra"><br></div><div class="gmail_extra">This interface assumes each subgroup may appear 0 or 1 times. You could maybe keep track of the number of matches more precisely by using {Type} instead of {Unit} and using a type class to implement type-level functions.</div><div class="gmail_extra"><br></div><div class="gmail_extra"><span style="font-family:monospace,monospace">con t : {Type} </span><span style="font-family:monospace,monospace">(* maps names of captured subgroups to type-level representation of number of matched fields *)</span><span style="font-family:monospace,monospace"> -> Type</span></div><div class="gmail_extra"><span style="font-family:monospace,monospace"><br></span></div><div class="gmail_extra"><font face="monospace, monospace">type one</font></div><div class="gmail_extra"><font face="monospace, monospace">type oneOrNone</font></div><div><font face="monospace, monospace"><br></font><span style="font-family:monospace,monospace"></span><div class="gmail_extra"><font face="monospace, monospace">class meet : Type -> Type -> Type</font></div><div class="gmail_extra"><font face="monospace, monospace">val meet_one_oneOrNone : weaken one oneOrNone oneOrNone</font></div><span style="font-family:monospace,monospace">val meet_oneOrNone_one : weaken oneOrNone one oneOrNone</span><div><span style="font-family:monospace,monospace">val meet_oneOrNone_oneOrNone : weaken oneOrNone oneOrNone oneOrNone</span></div><div><span style="font-family:monospace,monospace"><br></span></div><div class="gmail_extra">This makes the types more complicated, but I suspect (though I don't know for sure) that Ur/Web will be able to infer the extra stuff in any concrete (that is, monomorphic) use, so the user code will still look pretty. Here's how some of the functions look with this. The place weaken gets used is alt.</div><div class="gmail_extra"><br></div><div class="gmail_extra"><font face="monospace, monospace">val star : r ::: {Type} </font><span style="font-family:monospace,monospace">-></span><br></div><div class="gmail_extra"><div><span style="font-family:monospace,monospace">    t r -> t (map (fn _ => oneOrNo) r)</span></div></div><div class="gmail_extra"><span style="font-family:monospace,monospace"><br></span></div><div class="gmail_extra"><div><font face="monospace, monospace">val alt : r ::: {Type * Type * Type} -> s1 ::: {Type} -> s2 ::: {Type} -></font></div><div><font face="monospace, monospace">    [map fst3 r ~ s1] => [map snd3 r ~ s2] => [s1 ~ s2] </font><span style="font-family:monospace,monospace">=></span></div><div><span style="font-family:monospace,monospace">    $(map (fn </span><span style="font-family:monospace,monospace">(t1, t2, t3) => weaken t1 t2 t3</span><span style="font-family:monospace,monospace">) r)</span></div><div><span style="font-family:monospace,monospace">    t (map fst3 r ++ s1) -> t (map snd3 r ++ s2)</span></div><div><span style="font-family:monospace,monospace">    -> t (map thd3 r ++ map (fn _ => oneOrNo) (s1 ++ s2))</span></div></div><div class="gmail_extra"><br></div><div class="gmail_extra">You could extend the same sort of idea to types like oneOrMore and noneOrMore—useful if the underlying library can return a list of matches inside a + or *—by adding more cases to weaken.</div></div><div class="gmail_extra"><br></div><div class="gmail_extra">Here's a Haskell library that takes basically this approach: <a href="https://github.com/sweirich/dth/tree/master/popl17/src">https://github.com/sweirich/dth/tree/master/popl17/src</a></div><div class="gmail_extra"><br></div><div class="gmail_extra">Hope this helps!</div><div class="gmail_extra">Ziv</div><div class="gmail_extra"><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Feb 20, 2017 at 12:00 AM, Artyom Shalkhakov <span dir="ltr"><<a href="mailto:artyom.shalkhakov@gmail.com" target="_blank">artyom.shalkhakov@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="">2017-02-20 10:47 GMT+06:00  <span dir="ltr"><<a href="mailto:fold@tuta.io" target="_blank">fold@tuta.io</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  
    
  
  <div>
Maybe just define another attribute in basis.urs?<div><br></div><div>It would be much interesting to define a DSEL though. I have not seen any attempts to create a DSEL for regular expressions.</div><div><br></div></div></blockquote><div><br></div></span><div>Indeed! And it seems like it would be a nice exercise as well having some practical uses to it.</div><div><br></div><div>I envision something along the lines of:</div><div><br></div><div>datatype RegExp = ... (* constructors *)</div><div><br></div><div>type t (* abstract, not exported outside the module *)</div><div>val compile : RegExp -> t (* the trusted function *)</div><div>val matches : string -> t -> bool (* check if passed-in string matches the expression *)</div><div><br></div><div>And the implementation might use something unsafe (like a string, or an actual regexp object in JS). Then we could offload the interpretation of regexps to an off-the-shelf library. The [compile] function would print and escape the AST to a regexp string, and the Ur/Web compiler might actually optimize all of this away.</div><div><br></div><div>If we are to take care of matching subgroups, that would require a more complicated type. I guess that should be doable as well, but I don't see immediately how to handle this.</div><span class=""><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div><br><br>20. Feb 2017 16:28 by <a href="mailto:artyom.shalkhakov@gmail.com" rel="noopener noreferrer" target="_blank">artyom.shalkhakov@gmail.com</a>:<div><div class="m_-2208825993486552242h5"><br><br><blockquote class="m_-2208825993486552242m_-4979629669098642090tutanota_quote" style="border-left:1px solid #93a3b8;padding-left:10px;margin-left:5px"><div>Hello all,<div><br></div><div>'m doing form validation stuff, following examples on MDN. [1]<br></div><div><br></div><div>It seems like Ur/Web doesn't handle regular expressions?</div><div><br></div><div>I guess it should not be too diffcult to define a DSEL in Ur/Web (just AST constructors and a few trusted functions: e.g. [compile : AST -> regexp], where [regexp] is an abstract type, or maybe just a string :-)) and have it work at least in the browser.</div><div><br></div><div>Could somebody point me in the right direction here?</div><div><br></div><div>-- <br><div class="m_-2208825993486552242m_-4979629669098642090gmail_signature">Cheers,<br>Artyom Shalkhakov<br></div><div class="m_-2208825993486552242m_-4979629669098642090gmail_signature"><br></div><div class="m_-2208825993486552242m_-4979629669098642090gmail_signature">[1] <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation" rel="noopener noreferrer" target="_blank">https://developer.mozilla.<wbr>org/en-US/docs/Web/Guide/HTML/<wbr>HTML5/Constraint_validation</a></div><div class="m_-2208825993486552242m_-4979629669098642090gmail_signature"><br></div>
</div></div></blockquote></div></div></div>  </div>

</blockquote></span></div><span class="HOEnZb"><font color="#888888"><br><br clear="all"><div><br></div>-- <br><div class="m_-2208825993486552242gmail_signature" data-smartmail="gmail_signature">Cheers,<br>Artyom Shalkhakov<br></div>
</font></span></div></div>
<br>______________________________<wbr>_________________<br>
Ur mailing list<br>
<a href="mailto:Ur@impredicative.com">Ur@impredicative.com</a><br>
<a href="http://www.impredicative.com/cgi-bin/mailman/listinfo/ur" rel="noreferrer" target="_blank">http://www.impredicative.com/<wbr>cgi-bin/mailman/listinfo/ur</a><br>
<br></blockquote></div><br></div>