<div dir="ltr">Awesome Chris, glad the idea was applicable!<div><br></div><div>Nice post on the topic, I hadn't thought of using this for more powerful validation of values.  Use of quasiquotes and such for validated literals is well known, but this approach allows compiletime validation of the results of arbitrary expressions and not just strings!  Very cool.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Aug 22, 2019 at 10:49 AM Christopher Done <<a href="mailto:chrisdone@gmail.com" target="_blank">chrisdone@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Wrote up here! <a href="https://chrisdone.com/posts/static-smart-constructors/" target="_blank">https://chrisdone.com/posts/static-smart-constructors/</a><div><br></div><div>This was totally blocking my library from becoming complete, I'm super happy I can proceed now.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 22 Aug 2019 at 17:09, Christopher Done <<a href="mailto:chrisdone@gmail.com" target="_blank">chrisdone@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978markdown-here-wrapper"><p style="margin:0px 0px 1.2em">Depending on how much syntactic overhead you’re happy with, you can go full type-safe:</p>
<pre style="font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978language-haskell" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;white-space:pre-wrap;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248);display:block"><span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-title" style="color:rgb(153,0,0);font-weight:bold">checkGrammar_3</span> :: <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">String</span>) -> <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">String</span>)))
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-title" style="color:rgb(153,0,0);font-weight:bold">checkGrammar_3</span> q = <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">do</span>
  <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> expr <- q
  [|| <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">if</span> valueFine $$(q)
      <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">then</span> pure (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> expr)
      <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">else</span> error <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-string" style="color:rgb(221,17,68)">"value is not fine"</span> ||]
</code></pre>
<pre style="font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978language-haskell" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;white-space:pre-wrap;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248);display:block">> $$($$(checkGrammar_3 [|| thename ||]))
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-string" style="color:rgb(221,17,68)">"Hello!"</span>
> $$($$(checkGrammar_3 [|| thename_empty ||]))

<interactive>:<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-number" style="color:rgb(0,128,128)">45</span>:<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-number" style="color:rgb(0,128,128)">4</span>: error:
    • <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">Exception</span> when trying to run compile-time code:
        value is not fine
</code></pre>
<p style="margin:0px 0px 1.2em">In my case it might even be a fine trade-off, because I’m favoring TH-based validation of a DSL where doing it with e.g. type-level lists and type families has worse type-inference and a higher price to pay in type-signatures. So I can make a “static-smart” constructor that looks more like:</p>
<pre style="font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978language-haskell" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;white-space:pre-wrap;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248);display:block"><span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-title" style="color:rgb(153,0,0);font-weight:bold">checkGrammar_3</span> :: <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">Tree</span> a)) -> <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">ValidTree</span> a))))
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-title" style="color:rgb(153,0,0);font-weight:bold">useValidTree</span> :: <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978hljs-type" style="color:rgb(68,85,136);font-weight:bold">ValidTree</span> a -> ...
</code></pre>
<p style="margin:0px 0px 1.2em">So you pay the cost once here, but when building the tree, which is more larger code, you don’t pay any cost, and there’s where it matters.</p>
<div title="MDH:RGVwZW5kaW5nIG9uIGhvdyBtdWNoIHN5bnRhY3RpYyBvdmVyaGVhZCB5b3UncmUgaGFwcHkgd2l0
aCwgeW91IGNhbiBnbyBmdWxsIHR5cGUtc2FmZTo8ZGl2Pjxicj48L2Rpdj48ZGl2PmBgYGhhc2tl
bGw8L2Rpdj48ZGl2PmNoZWNrR3JhbW1hcl8zIDo6IFEgKFRFeHAgU3RyaW5nKSAtJmd0OyBRIChU
RXhwIChRIChURXhwIFN0cmluZykpKTxicj5jaGVja0dyYW1tYXJfMyBxID0gZG88YnI+Jm5ic3A7
IFRFeHAgZXhwciAmbHQ7LSBxPGJyPiZuYnNwOyBbfHwgaWYgdmFsdWVGaW5lICQkKHEpPGJyPiZu
YnNwOyAmbmJzcDsgJm5ic3A7IHRoZW4gcHVyZSAoVEV4cCBleHByKTxicj4mbmJzcDsgJm5ic3A7
ICZuYnNwOyBlbHNlIGVycm9yICJ2YWx1ZSBpcyBub3QgZmluZSIgfHxdPGJyPjwvZGl2PjxkaXY+
YGBgPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5gYGBoYXNrZWxsPC9kaXY+PGRpdj4mZ3Q7ICQk
KCQkKGNoZWNrR3JhbW1hcl8zIFt8fCB0aGVuYW1lIHx8XSkpPGJyPiJIZWxsbyEiPGJyPiZndDsg
JCQoJCQoY2hlY2tHcmFtbWFyXzMgW3x8IHRoZW5hbWVfZW1wdHkgfHxdKSk8YnI+PGJyPiZsdDtp
bnRlcmFjdGl2ZSZndDs6NDU6NDogZXJyb3I6PGJyPiZuYnNwOyAmbmJzcDsg4oCiIEV4Y2VwdGlv
biB3aGVuIHRyeWluZyB0byBydW4gY29tcGlsZS10aW1lIGNvZGU6PGJyPiZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyB2YWx1ZSBpcyBub3QgZmluZTxicj48L2Rpdj48ZGl2PmBgYDwvZGl2Pjxk
aXY+PGJyPjwvZGl2PjxkaXY+SW4gbXkgY2FzZSBpdCBtaWdodCBldmVuIGJlIGEgZmluZSB0cmFk
ZS1vZmYsIGJlY2F1c2UgSSdtIGZhdm9yaW5nIFRILWJhc2VkIHZhbGlkYXRpb24gb2YgYSBEU0wg
d2hlcmUgZG9pbmcgaXQgd2l0aCBlLmcuIHR5cGUtbGV2ZWwgbGlzdHMgYW5kIHR5cGUgZmFtaWxp
ZXMgaGFzIHdvcnNlIHR5cGUtaW5mZXJlbmNlIGFuZCBhIGhpZ2hlciBwcmljZSB0byBwYXkgaW4g
dHlwZS1zaWduYXR1cmVzLiBTbyBJIGNhbiBtYWtlIGEgInN0YXRpYy1zbWFydCIgY29uc3RydWN0
b3IgdGhhdCBsb29rcyBtb3JlIGxpa2U6PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5gYGBoYXNr
ZWxsPC9kaXY+PGRpdj5jaGVja0dyYW1tYXJfMyA6OiBRIChURXhwIChUcmVlIGEpKSAtJmd0OyBR
IChURXhwIChRIChURXhwIChWYWxpZFRyZWUgYSkpKSk8YnI+PC9kaXY+PGRpdj51c2VWYWxpZFRy
ZWUgOjogVmFsaWRUcmVlIGEgLSZndDsgLi4uPC9kaXY+PGRpdj5gYGA8L2Rpdj48ZGl2Pjxicj48
L2Rpdj48ZGl2PlNvIHlvdSBwYXkgdGhlIGNvc3Qgb25jZSBoZXJlLCBidXQgd2hlbiBidWlsZGlu
ZyB0aGUgdHJlZSwgd2hpY2ggaXMgbW9yZSBsYXJnZXIgY29kZSwgeW91IGRvbid0IHBheSBhbnkg
Y29zdCwgYW5kIHRoZXJlJ3Mgd2hlcmUgaXQgbWF0dGVycy48L2Rpdj48ZGl2Pjxicj48L2Rpdj4=" style="height:0px;width:0px;max-height:0px;max-width:0px;overflow:hidden;font-size:0em;padding:0px;margin:0px"></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 22 Aug 2019 at 16:40, Christopher Done <<a href="mailto:chrisdone@gmail.com" target="_blank">chrisdone@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539markdown-here-wrapper"><p style="margin:0px 0px 1.2em">Hurray! It works!</p>
<pre style="font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539language-haskell" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;white-space:pre-wrap;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248);display:block"><span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-pragma" style="color:rgb(153,153,153);font-weight:bold">{-# LANGUAGE TemplateHaskell #-}</span>
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-import"><span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">import</span> Language.Haskell.TH.Syntax</span>
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-import"><span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">import</span> <a href="http://Language.Haskell.TH" target="_blank">Language.Haskell.TH</a></span>
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-import"><span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">import</span> Language.Haskell.TH.Lift <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-container">()</span></span>

<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-title" style="color:rgb(153,0,0);font-weight:bold">valueFine</span> :: <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">String</span> -> <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Bool</span>
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-title" style="color:rgb(153,0,0);font-weight:bold">valueFine</span> = not . null

<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-title" style="color:rgb(153,0,0);font-weight:bold">checkGrammar_2</span> :: <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Name</span> -> <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">ExpQ</span>
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-title" style="color:rgb(153,0,0);font-weight:bold">checkGrammar_2</span> name =
  [| <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">if</span> valueFine $(varE name)
      <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">then</span> varE name
      <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">else</span> error <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"value isn't fine"</span> |]

<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-title" style="color:rgb(153,0,0);font-weight:bold">thename</span> :: [<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Char</span>]
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-title" style="color:rgb(153,0,0);font-weight:bold">thename</span> = <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"Hello!"</span>

<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-title" style="color:rgb(153,0,0);font-weight:bold">thename_empty</span> :: [<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Char</span>]
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-title" style="color:rgb(153,0,0);font-weight:bold">thename_empty</span> = <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">""</span>
</code></pre>
<p style="margin:0px 0px 1.2em">The output:</p>
<pre style="font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539language-haskell" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;white-space:pre-wrap;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248);display:block">> :t $(checkGrammar_2 'thename)
$(checkGrammar_2 'thename) :: <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">ExpQ</span>
> :t $($(checkGrammar_2 'thename))
$($(checkGrammar_2 'thename)) :: [<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Char</span>]
> $($(checkGrammar_2 'thename))
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"Hello!"</span>
> $($(checkGrammar_2 'thename_empty))

<interactive>:<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-number" style="color:rgb(0,128,128)">49</span>:<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-number" style="color:rgb(0,128,128)">1</span>: error:
    • <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Exception</span> when trying to run compile-time code:
        value isn't fine
<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">CallStack</span> (from <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">HasCallStack</span>):
  error, called at <interactive>:<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-number" style="color:rgb(0,128,128)">49</span>:<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-number" style="color:rgb(0,128,128)">5</span> <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">in</span> interactive:<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Ghci2</span>
      <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Code</span>: (<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">if</span> valueFine thename_empty <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">then</span>
                 varE
                   ((<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Name</span> (mkOccName <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"thename_empty"</span>))
                      (((<span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">NameG</span> <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">VarName</span>) (mkPkgName <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"main"</span>)) (mkModName <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"Main"</span>)))
             <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">else</span>
                 error <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"value isn't fine"</span>)
    • <span class="gmail-m_-5147857317324297857gmail-m_8496263745799229456gmail-m_413315328870812151gmail-m_4217957532298046978gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">In</span> the untyped splice: $($(checkGrammar_2 'thename_empty))
</code></pre>
<p style="margin:0px 0px 1.2em">Thanks Michael! You’re a star! </p>
<p style="margin:0px 0px 1.2em">I should document this in a gist or blog post or something as a technique for DSL checking.</p>
<div title="MDH:SHVycmF5ISBJdCB3b3JrcyE8ZGl2Pjxicj48L2Rpdj48ZGl2PmBgYGhhc2tlbGw8L2Rpdj48ZGl2
PnstIyBMQU5HVUFHRSBUZW1wbGF0ZUhhc2tlbGwgIy19PGJyPmltcG9ydCBMYW5ndWFnZS5IYXNr
ZWxsLlRILlN5bnRheDxicj5pbXBvcnQgTGFuZ3VhZ2UuSGFza2VsbC5USDxicj5pbXBvcnQgTGFu
Z3VhZ2UuSGFza2VsbC5USC5MaWZ0ICgpPGJyPjxicj52YWx1ZUZpbmUgOjogU3RyaW5nIC0mZ3Q7
IEJvb2w8YnI+dmFsdWVGaW5lID0gbm90IC4gbnVsbDxicj48YnI+Y2hlY2tHcmFtbWFyXzIgOjog
TmFtZSAtJmd0OyBFeHBRPGJyPmNoZWNrR3JhbW1hcl8yIG5hbWUgPTxicj4mbmJzcDsgW3wgaWYg
dmFsdWVGaW5lICQodmFyRSBuYW1lKTxicj4mbmJzcDsgJm5ic3A7ICZuYnNwOyB0aGVuIHZhckUg
bmFtZTxicj4mbmJzcDsgJm5ic3A7ICZuYnNwOyBlbHNlIGVycm9yICJ2YWx1ZSBpc24ndCBmaW5l
IiB8XTxicj48YnI+dGhlbmFtZSA6OiBbQ2hhcl08YnI+dGhlbmFtZSA9ICJIZWxsbyEiPGJyPjxi
cj50aGVuYW1lX2VtcHR5IDo6IFtDaGFyXTxicj50aGVuYW1lX2VtcHR5ID0gIiI8YnI+PC9kaXY+
PGRpdj5gYGA8L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PlRoZSBvdXRwdXQ6PC9kaXY+PGRpdj48
YnI+PC9kaXY+PGRpdj5gYGBoYXNrZWxsPC9kaXY+PGRpdj4mZ3Q7IDp0ICQoY2hlY2tHcmFtbWFy
XzIgJ3RoZW5hbWUpPGJyPiQoY2hlY2tHcmFtbWFyXzIgJ3RoZW5hbWUpIDo6IEV4cFE8YnI+Jmd0
OyA6dCAkKCQoY2hlY2tHcmFtbWFyXzIgJ3RoZW5hbWUpKTxicj4kKCQoY2hlY2tHcmFtbWFyXzIg
J3RoZW5hbWUpKSA6OiBbQ2hhcl08YnI+Jmd0OyAkKCQoY2hlY2tHcmFtbWFyXzIgJ3RoZW5hbWUp
KTxicj4iSGVsbG8hIjxicj4mZ3Q7ICQoJChjaGVja0dyYW1tYXJfMiAndGhlbmFtZV9lbXB0eSkp
PGJyPjxicj4mbHQ7aW50ZXJhY3RpdmUmZ3Q7OjQ5OjE6IGVycm9yOjxicj4mbmJzcDsgJm5ic3A7
IOKAoiBFeGNlcHRpb24gd2hlbiB0cnlpbmcgdG8gcnVuIGNvbXBpbGUtdGltZSBjb2RlOjxicj4m
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgdmFsdWUgaXNuJ3QgZmluZTxicj5DYWxsU3RhY2sg
KGZyb20gSGFzQ2FsbFN0YWNrKTo8YnI+Jm5ic3A7IGVycm9yLCBjYWxsZWQgYXQgJmx0O2ludGVy
YWN0aXZlJmd0Ozo0OTo1IGluIGludGVyYWN0aXZlOkdoY2kyPGJyPiZuYnNwOyAmbmJzcDsgJm5i
c3A7IENvZGU6IChpZiB2YWx1ZUZpbmUgdGhlbmFtZV9lbXB0eSB0aGVuPGJyPiZuYnNwOyAmbmJz
cDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7dmFyRTxi
cj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7
ICZuYnNwOyAmbmJzcDsoKE5hbWUgKG1rT2NjTmFtZSAidGhlbmFtZV9lbXB0eSIpKTxicj4mbmJz
cDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7ICgoKE5hbWVHIFZhck5hbWUpIChta1BrZ05hbWUgIm1haW4iKSkgKG1r
TW9kTmFtZSAiTWFpbiIpKSk8YnI+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ZWxzZTxicj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwO2Vycm9yICJ2YWx1ZSBpc24ndCBmaW5lIik8YnI+Jm5i
c3A7ICZuYnNwOyDigKIgSW4gdGhlIHVudHlwZWQgc3BsaWNlOiAkKCQoY2hlY2tHcmFtbWFyXzIg
J3RoZW5hbWVfZW1wdHkpKTxicj48L2Rpdj48ZGl2PmBgYDwvZGl2PjxkaXY+PGJyPjwvZGl2Pjxk
aXY+VGhhbmtzIE1pY2hhZWwhIFlvdSdyZSBhIHN0YXIhJm5ic3A7PC9kaXY+PGRpdj48YnI+PC9k
aXY+PGRpdj5JIHNob3VsZCBkb2N1bWVudCB0aGlzIGluIGEgZ2lzdCBvciBibG9nIHBvc3Qgb3Ig
c29tZXRoaW5nIGFzIGEgdGVjaG5pcXVlIGZvciBEU0wgY2hlY2tpbmcuPC9kaXY+" style="height:0px;width:0px;max-height:0px;max-width:0px;overflow:hidden;font-size:0em;padding:0px;margin:0px"></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 22 Aug 2019 at 16:26, Christopher Done <<a href="mailto:chrisdone@gmail.com" target="_blank">chrisdone@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">I considered an expression-within-an-expression but thought a stage-restriction would break it. Maybe not! Let me go test it!</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 21 Aug 2019 at 17:31, Michael Sloan <<a href="mailto:mgsloan@gmail.com" target="_blank">mgsloan@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">One potential solution here is to have checkGrammar_take2 return an<br>
expression which returns an expression.  I haven't tried compiling<br>
this, but something roughly like:<br>
<br>
checkGrammar_2 name = [| if valueFine $(varE name) then varE name else<br>
error "value isn't fine" |]<br>
<br>
Then it'd be used like $($(checkGrammar_2 'thename)).  The th-orphans<br>
package can also be useful for this because it provides Lift instances<br>
for the TH AST.<br>
<br>
-Michael<br>
<br>
On Tue, Aug 20, 2019 at 10:36 AM Christopher Done <<a href="mailto:chrisdone@gmail.com" target="_blank">chrisdone@gmail.com</a>> wrote:<br>
><br>
> Hi all,<br>
><br>
> Do we have already a syntax for ‘foo that also contains the typed value like TExp?<br>
><br>
> I have e.g. an AST that I want to do more static checks on it that aren’t as convenient to do in the type system. Here’s an example:<br>
><br>
> -- | Check the grammar spec to produce a grammar.<br>
> checkGrammar :: (SchemaName, [(SchemaName, Schema)]) -> Q Exp<br>
> checkGrammar (toplevel, rules) =<br>
>   if M.size rulesMap /= length rules<br>
>     then error "Duplicate rule names in grammar."<br>
>     else lift (Grammar {grammarToplevel = toplevel, grammarRules = rulesMap})<br>
>   where<br>
>     rulesMap = M.fromList rules<br>
><br>
> -- | Grammar for Haskell.<br>
> grammar :: Grammar<br>
> grammar = $(checkGrammar $ runDefine $ mdo<br>
>   -- General expression<br>
>   expression       <- rule "Expression" (ChoiceSchema [variable, constructor, parentheses<br>
>                                                       ,tuple, let', application, string])<br>
>   application      <- rule "Application" (CompositeSchema [expression, expression])<br>
>   parentheses      <- rule "Parentheses" (CompositeSchema [openParenSchema, expression, closeParenSchema])<br>
><br>
> ...<br>
>  pure expression)<br>
><br>
> Here I do a trivial check for duplicates. After I’ve checked the<br>
> expression at compile-time, I Lift it so that it can be used at<br>
> runtime. That’s pretty good. But some types like (a -> b) don’t Lift. So<br>
> an alternative would be:<br>
><br>
> grammar = $(checkGrammar_take2 thename 'thename)<br>
><br>
> In which checkGrammar_take2 would:<br>
><br>
> Use thename at compile-time for a check.<br>
> If the check passes, then return (VarE thename)<br>
><br>
> E.g.<br>
><br>
> checkGrammar_take2 value name = if valueFine value then varE name else<br>
> error "value isn't fine"<br>
><br>
> That’s actually quite a good solution because it avoids a lift, and I<br>
> didn’t transform the AST. It’s also more efficient than lifting.<br>
><br>
> But there’s no checked relationship between thename and ‘thename.<br>
> checkGrammar_take2 has no way of knowing that they refer to the same<br>
> thing. See?<br>
><br>
> Hence, if I could get e.g. `thename to produce both the value and a<br>
> name for the value, that would be cool. My gist doesn’t go this<br>
> far. It might look like this:<br>
><br>
> checkGrammar_take2 namedValue = if valueFine (getValue namedValue) then getExp namedValue else error "value isn't fine"<br>
><br>
> and call it like:<br>
><br>
> mygrammar = checkGrammar_take2 `thename<br>
><br>
> So the semantics would be roughly similar to<br>
><br>
> [|| thename ||] :: TExp a<br>
><br>
> but you’d get<br>
><br>
> `thename :: Named a<br>
><br>
> where<br>
><br>
> data Named a = { namedThing :: a, nameOfThing :: Name }<br>
><br>
> I feel like the more DSLs I design, the more I’d like something like this to perform my static checks.<br>
><br>
> Cheers,<br>
><br>
> Chris<br>
><br>
> _______________________________________________<br>
> Haskell-Cafe mailing list<br>
> To (un)subscribe, modify options or view archives go to:<br>
> <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
> Only members subscribed via the mailman list are allowed to post.<br>
</blockquote></div>
</blockquote></div>
</blockquote></div>
</blockquote></div>
</blockquote></div>