[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