<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>Thanks for all the thoughts on the language!  My responses:<br>
    </p>
    <div class="moz-cite-prefix">On 3/17/21 6:36 PM, Joachim Breitner
      wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">I got “Some constructor unification variables are undetermined in
declaration” for unification variables in unused code (e.g. when I
stopped using some temporary recursive helper function). Made me wonder
if undetermined variables could be maybe be allowed in unused code, so
that I don’t have to comment out that code?</pre>
    </blockquote>
    Maybe, but that's not as simple of an idea as it would be in classic
    Hindley-Milner type inference.  The reason is that, in general, not
    all values of remaining unification variables are legal.  There are
    other lingering constraints, including disjointness of rows, so it
    really would involve adding a somewhat-interesting solver.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">In terms of developer usability, I was kinda expecting a “urweb watch”
mode that, upon changes to the sources, recompiles, restarts the
server, and maybe reloads the client. But not a big deal, I am just
spoiled.</pre>
    </blockquote>
    I sometimes use my own simple external scripting to that end
    (watching the file system for changes), for interactive demos. 
    However, for better or worse, large projects will take long enough
    to compile that I would think an unpleasant user experience could
    follow from automatic recompilation.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">On the server side, the old app didn’t need any persistent state (it
only associated state with open connections), but in Ur/Web I had to
use the database to communicate between the open connections.</pre>
    </blockquote>
    Yeah, it makes sense that that use case would require a bit of
    arbitrary-feeling setup, to use the SQL database for
    cross-HTTP-request state.  It's not at all the kind of scenario I
    had in mind in designing the language.  However, it would be easy
    enough to wrap all use of SQL in a functor exporting a pretty
    natural interface.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">The “serialized” type
constructor was a bit odd; I wonder why can’t I just use the type
directly and instead have to serialize/deserialize, but I kinda see the
point.</pre>
    </blockquote>
    I'm trying to remember why I introduced that type family years ago! 
    Part of it is that I wanted to use type classes to control which
    types are allowed in SQL code values, so that functors may declare
    their expectations appropriately.  Serialization fails at compile
    time when used on inappropriate types, and that failure logic uses
    arbitrary compiler code, not a nice set of type-class instances.  So
    it can be seen as kind of a trick to get arbitrary type-level
    approval code into a type-class instance.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">Ur/Web doesn’t support canvas drawing out of the box, but I found 
<a class="moz-txt-link-freetext" href="https://github.com/fabriceleal/urweb-canvas/">https://github.com/fabriceleal/urweb-canvas/</a>. 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.</pre>
    </blockquote>
    <p>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!).</p>
    <p>In my experience, wrapping JavaScript libraries isn't a
      significant effort bottleneck for real projects, but you've raised
      a number of good ideas for improving the FFI experience, which I
      would at least be glad to see come in as pull requests, after some
      discussion on this mailing list.<br>
    </p>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">But maybe the need to import JS libraries is just rare enough.</pre>
    </blockquote>
    Speaking only for myself, there have been precious few JavaScript
    libraries that I've ever wanted to connect to from Ur/Web.  I think
    the tally stands at about five since 2006.  I find that most
    libraries used in web programming are making up for design mistakes
    in other libraries, Ponzi-scheme style.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">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></pre>
    </blockquote>
    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.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">I found it odd that I cannot have mutually recursive values of type
transaction (which is a function of sorts), and have to add unit
arguments. Probably a ML programmer finds that restriction natural,
with my Haskell background it was odd.</pre>
    </blockquote>
    Right: Ur/Web has eager evaluation, so it is not coherent to allow
    recursive definition of just anything!  And it's an interesting
    question how such a language can allow introduction of new classes
    of recursive things in libraries, rather than as built-in language
    features.  Nothing about transactions is built into the Ur/Web core
    language.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">Similarly, at one point I tried to use `s : source xbody <- source …`
for the main views (because why introduce a data type when there is
only a single function from that data type?). But that ran afoul a
similar problem, as … may not refer to `s`. Again, I was probably
thinking too Haskelly.</pre>
    </blockquote>
    <p>That example is actually easy to patch: initialize `s` with dummy
      code, then overwrite it with the new content, which may mention
      `s`.  (The only word of warning here is that the overwrite must
      happen in client-side code.)</p>
    <p>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.<br>
    </p>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">No derivation of show, soo useful for debugging and prototyping?
Not even for eq?</pre>
    </blockquote>
    That would be great to see someone add!  You can actually get pretty
    good generic printing using conversion to JSON already, though.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">I missed a less heavy variant `let`. Especially one that lines up
nicely with do notation (`let val x = y in e end` is a mouthful, and
adds indentation). I resorted to `x <- return y; e`, not sure how bad
that is.</pre>
    </blockquote>
    I tried to add a lighter-weight version way back when, and I ran
    into some aggravating conflict in the parser generator.  Yes, the
    version with `return` is what I write myself these days.  I'd love
    to see a patch adding a lighter-weight version that doesn't break
    other notations!<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">No eq for tuples predie</pre>
    </blockquote>
    There is a generic implementation in <a moz-do-not-send="true"
      href="https://github.com/urweb/upo/blob/master/record.urs">UPO</a>. 
    (It's important to keep in mind that tuples are a special case of
    records in Ur/Web.)<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">Irrefutable patterns in `p <- e; e` are useful, and I missed them also
in `fn p => …`, especially when working with association lists.</pre>
    </blockquote>
    Actually, irrefutable patterns <i>do</i> work with anonymous
    functions!  Something else must have gone wrong to throw you off. 
    Maybe your example was missing parentheses around the pattern.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">The CSS parser didn’t like some property names I was using:
“Invalid string -webkit-hyphens passed to 'property'”</pre>
    </blockquote>
    Ah, sounds like I should just change the function that validates
    property names.  The implementations in <a moz-do-not-send="true"
      href="https://github.com/urweb/urweb/blob/master/src/mono_opt.sml#L186">SML</a>
    and <a moz-do-not-send="true"
      href="https://github.com/urweb/urweb/blob/master/lib/js/urweb.js#L3379">JavaScript</a>
    both force property names to start with letters or underscores.  Is
    it clear that hyphens should be allowed as well, with no further
    restrictions?<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">Similarly, and just like almost any statically typed view on HTML,
there are always tags and properties missing. In my case, tabIndex. No
big deal, just minor friction.</pre>
    </blockquote>
    I'll be happy to take a pull request adding an innocuous-sounding
    feature like that one.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">At some point I briefly used variants, but the syntax was a bit
verbose, and they didn’t add anything of value over data types at that
point. But later I think I could have done fun fancy generic stuff with
them if I had them. Still makes me wonder if we can’t simply have both
(e.g. variants everywhere).  Is it that type inference suffers too
much?</pre>
    </blockquote>
    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.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">Urweb generates data base schemas to create databases. But it seems the
problem of migrating existing data from prior versions to the schema of
new versions does not get any built-in help in Ur/Web. Ideally somehow
Ur/Web allows me to specify (declaratively or by code) how to migrate
from old versions, and I get the end-to-end static typing support that
I came to Ur/Web for. But it’s obviously a hard problem, and discussed
before (e.g. at <a class="moz-txt-link-freetext" href="https://github.com/urweb/urweb/issues/65">https://github.com/urweb/urweb/issues/65</a>). Still, I
wonder how production users of Ur/Web deal with this?</pre>
    </blockquote>
    I write my own migrations outside Ur/Web.  It's typically fairly
    easy with SQL schema-manipulation commands.  I also agree it would
    be nice to have a generic solution in the language tooling; all the
    relevant information is already kept, with the main complication
    being how to make it possible to talk about old versions of a
    schema.  That could actually get pretty involved, what with Ur/Web's
    commitment to allowing modules to have private tables.  IMO, it
    would be an antipattern to force consideration of an application's
    database schema as a monolithic, flat definition.  I also use <a
      moz-do-not-send="true" href="https://github.com/fordfrog/apgdiff">apgdiff</a>
    sometimes for the dumbest possible automatic schema adaptation, and
    it usually works.<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">It seems that Ur/Web projects are so nicely self-contained, they should
be ideal candidates for serverless deployment. I guess one can’t easily
use Amazon Lambda, because the server is actually stateful (to persist
these client connections), but I could still imagine that some auto-
deploy-from-github-repo-without-configuration (like netlify etc.
offer), including data base etc. might be a nice add-on at some point,
so that it takes just minutes from writing your foo.urp to having a
live site.</pre>
    </blockquote>
    Agreed!  I'd love to see a pull request with that kind of scripting,
    even included in the main project repo (though I believe it should
    be quite doable with minimal code from an unprivileged position).<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">I imagine if I didn’t have to deal with Canvas,</pre>
    </blockquote>
    I agree it's fair to point out lack of an existing library for a
    standard HTML feature was a fundamental obstacle, but...<br>
    <blockquote type="cite"
cite="mid:d462b6b8f39553dc2178cc081462667c93ba7af1.camel@joachim-breitner.de">
      <pre class="moz-quote-pre" wrap="">and maybe went for something less AJAXy and more
classical web programming with links and POSTs,</pre>
    </blockquote>
    ...here I have to disagree.  I'll continue claiming that Ur/Web
    supports AJAXy programming better than anything else out there!  I
    don't put many links or old-school forms in Ur/Web applications I
    write these days.  (However, many web API requests use POSTs today,
    so I'm not sure what that part of your characterization is meant to
    draw attention to.)
  </body>
</html>