[Ur] Ur/Web first impressions

Joachim Breitner mail at joachim-breitner.de
Thu Mar 18 14:20:04 EDT 2021


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/





More information about the Ur mailing list