<div dir="ltr"><div>Summary:<br></div><div><br></div><div>I have been attempting to extend the Crud2 demo to include a foreign-key field and provide a data-bound widget (using a <select> element containing multiple <option> elements) to allow the user to easily edit the foreign-key field.</div><div><br></div><div>My code is giving compile errors such as "unification failure" and "incompatible constructors", which can be seen here:</div><div><br></div><div><a href="https://github.com/StefanScott/urweb-crud2foreign/issues/1">https://github.com/StefanScott/urweb-crud2foreign/issues/1</a><br></div><div><br></div><div>Apparently these compile errors are happening because:</div><div><br></div><div>- My code instantiates functions Show, Widget, WidgetPopulated and Parse, which are defined in crud.urs / crud.ur (in the Crud2 demo) and which are expected to return values of type xbody, xml, and db;</div><div><br></div><div>- Meanwhile, my code uses Top.queryX1 and Top.oneRowE1 which return values of "transactional" types - instead of the desired types xbody, xml and db.</div><div><br></div><div>So it seems that I need to run the transactional SQL functions queryX1 and oneRowE1, grab their transactional output, and then from that somehow obtain values of the appropriate types, such as xbody, xml, db.</div><div><br></div><div>I am fairly sure that all that is needed is minor adjustment to the erroneous syntax currently being used by my code - but I have not been able to hit on the correct syntax yet. (The 3 alternative syntaxes which I've tried are illustrated further below.)</div><div><br></div><div>Thanks for any help!</div><div><br></div><div><br></div><div>Initial, oversimplified case (this works):</div><div><br></div><div>As an initial, oversimplified case, I extended the Crud2 demo by merely adding a *non-foreign-key* field called LocalStatus. This works fine, and can be seen in this small github repository:</div><div><br></div><div><a href="https://github.com/StefanScott/urweb-crud2local">https://github.com/StefanScott/urweb-crud2local</a></div><div><br></div><div>However, this approach is not very useful, as it merely "hard-codes" 3 'Status' values in the program text, and does not involve a "parent" table providing a foreign key. The next approach will attempt to resolve this, by creating a separate "parent" table 'Status'.</div><div><br></div><div><br></div><div>Next case (this doesn't work): </div><div><br></div><div>This case involves extending the Crud2 demo by adding a a new table 'status' and a *foreign-key* field t.ForeignStatus referencing status.Id.</div><div><br></div><div>This code is giving compile-time errors about about "record unification" or "incompatible constructors". The (currently non-working) code can be seen in a separate github repository here:</div><div><br></div><div><a href="https://github.com/StefanScott/urweb-crud2foreign">https://github.com/StefanScott/urweb-crud2foreign</a></div><div><br></div><div>To avoid cluttering up this mailing list, the compile errors (for the version of the code used in the above crud2foreign repo) have been reproduced as Issue 1 in the github repo, here:</div><div><br></div><div><a href="https://github.com/StefanScott/urweb-crud2foreign/issues/1">https://github.com/StefanScott/urweb-crud2foreign/issues/1</a></div><div><br></div><div><br></div><div>Background:</div><div><br></div><div>The above approaches attempt to extend the existing Crud2 demo, which is available here:</div><div><br></div><div><a href="http://www.impredicative.com/ur/demo/crud2.html">http://www.impredicative.com/ur/demo/crud2.html</a></div><div><br></div><div>Recall that the Crud2 demo involves a record of 6 functions (Nam, Show, Widget, WidgetPopulated, Parse, Inject), whose declarations are shown below:</div><div><br></div><div>{Nam : string,</div><div> Show : db -> xbody,</div><div> Widget : nm :: Name -> xml form [] [nm = widget],</div><div> WidgetPopulated : nm :: Name -> db -> xml form [] [nm = widget],</div><div> Parse : widget -> db,</div><div> Inject : sql_injectable db}</div><div><br></div><div>Informally, the functions Show, Widget, WidgetPopulated and Parse do the following:</div><div><br></div><div>- The function Show accepts a db and returns an xbody.</div><div><br></div><div>- The function Widget accepts a nm of kind Name, and returns an xml. (If the widget implements a data-bound dropdown, then it might contain a <select> element, in turn containing multiple <option> elements).</div><div><br></div><div>- The function WidgetPopulated accepts a nm of kind Name and a db, and returns an xml. (If the widget implements a data-bound dropdown, then it might contain a <select> element, in turn containing multiple <option> elements).</div><div><br></div><div>- The function Parse accepts a widget and returns a db.</div><div><br></div><div>To define Show, Widget, WidgetPopulated and Parse, I am using the functions Top.QueryX1 and Top.oneRowE1, which are documented in the excellent chatroom tutorial: <a href="http://adam.chlipala.net/papers/UrWebPOPL15/UrWebPOPL15.pdf">http://adam.chlipala.net/papers/UrWebPOPL15/UrWebPOPL15.pdf</a> (eg, see page 2 for example usage, and see page 3 for nice English-language explanations of that these functions are intended to do).</div><div><br></div><div>When compiling crud2foreign, the compiler give various errors about "record unification" or "incompatible constructors".</div><div><br></div><div>So my code is obviously not producing the correct types.</div><div><br></div><div><br></div><div>Attempting various alternative syntaxes (none of these work):</div><div><br></div><div>I have been attempting various syntax alternatives (playing around with the semi-colon and the 'return'), but they have all been incorrect. </div><div><br></div><div>(1) Below are 3 (non-working!) syntax alternatives I have attempted for the definition of Show:</div><div><br></div><div>Show = (fn fs =></div><div>  statusNam <- oneRowE1 (SELECT Nam FROM status WHERE Id = {[fs]});</div><div>  return;</div><div>  <xml>{statusNam}</xml>)</div><div><br></div><div>Show = (fn fs =></div><div>  statusNam <- oneRowE1 (SELECT Nam FROM status WHERE Id = {[fs]});</div><div>  return statusNam;</div><div>  <xml>{statusNam}</xml>)</div><div><br></div><div>Show = (fn fs =></div><div>  <xml>{oneRowE1 (SELECT Nam FROM status WHERE Id = {[fs]})}</xml>)</div><div><br></div><div>(2) Below are the corresponding 3 (non-working!) syntax alternatives I have attempted for the definition of Widget (and similar code is used for WidgetPopulated, which simply accepts an additional argument of type db):</div><div><br></div><div>Widget = (fn [nm :: Name] => </div><div>statusOptions <- </div><div>  queryX1 (SELECT Id, Nam FROM status ORDER BY Nam) </div><div>  (fn r => <xml><coption value={r.Id}>{r.Nam}</coption></xml>);</div><div>  return;</div><div>  <xml></div><div>    <select{nm}></div><div>      {statusOptions}</div><div>    </select></div><div>  </xml>)</div><div><br></div><div>Widget = (fn [nm :: Name] => </div><div>statusOptions <- </div><div>  queryX1 (SELECT Id, Nam FROM status ORDER BY Nam) </div><div>  (fn r => <xml><coption value={r.Id}>{r.Nam}</coption></xml>);</div><div>  return statusOptions;</div><div>  <xml></div><div>    <select{nm}></div><div>      {statusOptions}</div><div>    </select></div><div>  </xml>)</div><div><br></div><div>Widget = (fn [nm :: Name] => </div><div>  <xml></div><div>    <select{nm}></div><div>      {queryX1 (SELECT Id, Nam FROM status ORDER BY Nam) </div><div>       (fn r => <xml><coption value={r.Id}>{r.Nam}</coption></xml>)}</div><div>    </select></div><div>  </xml>)</div><div><br></div><div>(2) And below are the corresponding 3 (non-working!) syntax alternatives I have attempted for the definition of Parse:</div><div><br></div><div>Parse = (fn fsNam =></div><div>  fsId <- oneRowE1 (SELECT Id FROM status WHERE Nam = {[fsNam]});</div><div>  return fsId;</div><div>  fsId)</div><div><br></div><div>Parse = (fn fsNam =></div><div>  fsId <- oneRowE1 (SELECT Id FROM status WHERE Nam = {[fsNam]});</div><div>  return;</div><div>  fsId)</div><div><br></div><div>Parse = (fn fsNam =></div><div>  oneRowE1 (SELECT Id FROM status WHERE Nam = {[fsNam]}))</div><div><br></div><div>In the absence of more detailed documentation and examples of how to use functions such as queryX1 and oneRowE1 to write transactional code and extract expressions, the above attempts are just clumsy shots in the dark by an Ur/Web novice.</div><div><br></div><div><br></div><div>Discussion:</div><div><br></div><div>Examining top.urs, the declaration of queryX1 is:</div><div><br></div><div>val queryX1 : nm ::: Name -> fs ::: {Type} -> ctx ::: {Unit} -> inp ::: {Type}</div><div>              -> sql_query [] [] [nm = fs] []</div><div>              -> ($fs -> xml ctx inp [])</div><div>              -> transaction (xml ctx inp [])</div><div><br></div><div>And the declaration of oneRowE1 is:</div><div><br></div><div>val oneRowE1 : tabs ::: {Unit} -> nm ::: Name -> t ::: Type</div><div>               -> [tabs ~ [nm]] =></div><div>    sql_query [] [] (mapU [] tabs) [nm = t]</div><div>    -> transaction t</div><div><br></div><div><br></div><div>Aside:</div><div><br></div><div>There is a bit of discussion about the absolutely essential files top.urs / top.ur in the PDF manual, and online here:</div><div><br></div><div><a href="http://enn.github.io/urweb-doc/node31.html">http://enn.github.io/urweb-doc/node31.html</a></div><div><br></div><div>Other than that, the only documentation appears to be the source code of the Ur/Web compiler itself - plus the very helpful descriptions of queryX1 and oneRowE1 in the chatroom tutorial: <a href="http://adam.chlipala.net/papers/UrWebPOPL15/UrWebPOPL15.pdf">http://adam.chlipala.net/papers/UrWebPOPL15/UrWebPOPL15.pdf</a></div><div><br></div><div><br></div><div>Further discussion:</div><div><br></div><div>Meanwhile, examining the code in crud.urs / crud.ur reveals that the functions Show, Widget, WidgetPopulated, and Parse are not expected to return "transactional" types - instead, they are expected to return types involving xbody, xml and db:</div><div><br></div><div>Show : db -> xbody,</div><div>Widget : nm :: Name -> xml form [] [nm = widget],</div><div>WidgetPopulated : nm :: Name -> db -> xml form [] [nm = widget],</div><div>Parse : widget -> db,</div><div><br></div><div>Therefore, I have been trying to run queryX1 and oneRowE1 and then somehow obtain values of types compatible with what crud.urs / crud.ur expects.</div><div><br></div><div>I suspect that the overall context involved in the chatroom example might be different from the context involved the Crud2 demo - which would mean that the code from the chatroom example cannot be used directly in my crud2foreign code, which needs to be compatible with the Crud2 demo.</div><div><br></div><div>Thanks for any help!</div><div><br></div><div>- Scott</div><div><br></div><div><br></div></div>