[Ur] Ur/Web first impressions

Ziv Scully zivscully at gmail.com
Thu Mar 18 16:02:03 EDT 2021


On the topic of whether variants would clean up your last few examples:

Off the top of my head (i.e., modulo some number of compiler errors...),
here's how you'd write a generic "get" function for variants and homogenous
records.

fun get [fields ::: {Unit}] [t ::: Type] (f : folder fields)
        (vals : $(mapU t fields))
        (field : variant (mapU unit fields))

    = match field
            (mp [fn () => t] [fn () => unit -> t]

                (* You can maybe omit this `folder` argument. *)

                @(Folder.mp @@(fn () => t) @@fields @f)

                (fn [_ ::: Unit] (val : t) => (fn () => val))
                vals)


Here your color type would become variant [Black = unit, White = unit], and
forColor would become a special case of get.

Writing a "set" function is a bit harder using standard-library functions.
You want something like mp, but you need access to the field name in your
mapping function. You can use foldUR, or you can write a new flavor of mp
<https://github.com/vizziv/UrLib/blob/20e4c29c88f597951dd916ed941cdcdafaef1cba/UrLib/prelude.urs#L89>
that gives access to the field names.

If you decided this was all too much and wanted to write a less generic
version, then you'd end up with basically a syntactically noisier version
of what you already have with a color datatype.

In conclusion: this is all probably way too heavy for your use case, but as
Adam mentioned, it can be very useful when metaprogramming.

Ziv

On Thu, Mar 18, 2021 at 2:21 PM Joachim Breitner <mail at joachim-breitner.de>
wrote:

> Hi Adam,
>
> thanks for the responses!
>
>
> Am Donnerstag, den 18.03.2021, 09:51 -0400 schrieb Adam Chlipala:
> > > Ur/Web doesn’t support canvas drawing out of the box, but I found
> > > https://github.com/fabriceleal/urweb-canvas/. Using a library like
> that
> > > was simple enough. Unfortunately, it didn’t cover the full Canvas API
> > > yet, and it seemed that adding the missing functions would require more
> > > boiler plate than I wanted to write right now.
> >
> > I can see how that makes sense for a quick pilot to evaluate the
> > language, though I expect it's pretty cost-effective to extend that
> > library with general Canvas features, for any kind of production app
> > (and then everyone else gets to benefit from the improvements!).
>
> Absolutely! And _after_ having refactored “my” JS code and learned
> about how to FFI-integrate it, I probably would have been more
> confident in just extending the library :-)
>
> > > Obviously, I need to connect the above function to a source/signal with
> > > the game state. I found that this works, although I wonder if this is
> > > an idiomatic way to do so:
> > >
> > >           <canvas id={canvas_id} align="center" width=500 height=400/>
> > >           <dyn signal={
> > >             ui <- signal ui_state;
> > >             return <xml><active code={
> > >               drawDisplayState canvas_id (displayState ui);
> > >               return <xml></xml>
> > >             }/></xml>
> >  The idiomatic way would be to use the features of the FFI for adding
> > change listeners on signals.  You may have been thrown off by the
> > fact that the library you took as inspiration does no such thing!
> > You'll find JavaScript function "listen" documented briefly on page
> > 59 of the currently posted reference manual.
>
> Yes, I remembered that mention, but given that both the source and the
> code I want to invoke upon changes already lives in “Ur world” it felt
> wrong to reach for the FFI. And it was expressible with just non-FFI-
> features, as shown above… I guess either way is just a way to deal with
> the fact that I am doing something uncommon (running possibly effectful
> code upon changes to the signal).
>
> Given that it _is_ expressible with
> high-level abstractions (dyn+active) makes me wonder if there shouldn’t
> be a
>
>    Basis.listen : signal a -> transaction a -> transaction unit
>
> or so, with sufficient documentation about when to use it and what to
> keep in mind.
>
> But maybe I shouldn’t ask for exposing underlying primitives before I
> really needed them a few times – it could be that I’d learn more
> idiomatic ways and notice that they are really rarely needed.
>
>
> > However, I also think of the type `source xbody` as a bad code
> > smell.  It is usually better to put your fundamental data model in
> > sources and then derive HTML from them using <dyn> tags.
>
> That’s what I ended up doing in the end, and it’s probably cleaner.
> (Although a part of me, when it sees a data type T that is only
> deconstructed by a single function T -> A, wonders why not create
> values of type A directly. At least in a pure language.)
>
>
> >  That would be great to see someone add!  You can actually get pretty
> > good generic printing using conversion to JSON already, though.
>
> Ah, I didn’t look at the JSON stuff yet. Thanks for the hint!
>
> > > Irrefutable patterns in `p <- e; e` are useful, and I missed them also
> > > in `fn p => …`, especially when working with association lists.
> >  Actually, irrefutable patterns do work with anonymous functions!
> > Something else must have gone wrong to throw you off.  Maybe your
> > example was missing parentheses around the pattern.
>
> Indeed! I guess I didn’t try hard enough. That’s a relief :)
>
> > > The CSS parser didn’t like some property names I was using:
> > > “Invalid string -webkit-hyphens passed to 'property'”
> >  Ah, sounds like I should just change the function that validates
> > property names.  The implementations in SML and JavaScript both force
> > property names to start with letters or underscores.  Is it clear
> > that hyphens should be allowed as well, with no further restrictions?
>
> I hope the diagram at
> https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
> is the right one. Looks like it may start with a single hyphen, but
> that hyphen must be followed by letters or non-ASCII.
>
> >  I would like to see algebraic datatypes and polymorphic variants
> > unified in a complete rewrite of Ur/Web some day.  For now, variants
> > are really only worth using in connection with metaprogramming.  I
> > have almost never written code with a variant of known type.
>
> I had code like this:
>
>    datatype color = Black | White
>    type gameState = {
>      Goes_first : color,
>      Phase : phase,
>      Board : list (coord * option color),
>      Chosen : { Black : option int, White : option int },
>      Placed : { Black : option int, White : option int },
>    }
>
> and more such “records that are total maps from the set of colors” I
> wonder if using a variant for color would have allowed me to avoid
> helpers like the following
>
>    fun forColor r c = case c of
>      | White => r.White
>      | Black => r.Black
>
>    fun setColor r c x = case c of
>      | White => r -- #White ++ { White = x }
>      | Black => r -- #Black ++ { Black = x }
>
> or at least write them more nicely.
>
>
> Cheers,
> Joachim
>
> --
> Joachim Breitner
>   mail at joachim-breitner.de
>   http://www.joachim-breitner.de/
>
>
>
> _______________________________________________
> Ur mailing list
> Ur at impredicative.com
> http://www.impredicative.com/cgi-bin/mailman/listinfo/ur
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.impredicative.com/pipermail/ur/attachments/20210318/2ca1d976/attachment-0001.html>


More information about the Ur mailing list