<div dir="ltr"><div class="markdown-here-wrapper" style=""><p style="margin:0px 0px 1.2em!important">Depending on how much syntactic overhead you’re happy with, you can go full type-safe:</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="hljs language-haskell" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline;white-space:pre;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important;display:block;overflow-x:auto;padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248)"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">checkGrammar_3</span> :: <span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> <span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">String</span>) -> <span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> <span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">String</span>)))
<span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">checkGrammar_3</span> q = <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">do</span>
  <span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> expr <- q
  [|| <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">if</span> valueFine $$(q)
      <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">then</span> pure (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> expr)
      <span class="hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">else</span> error <span class="hljs-string" style="color:rgb(221,17,68)">"value is not fine"</span> ||]
</code></pre>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="hljs language-haskell" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline;white-space:pre;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important;display:block;overflow-x:auto;padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248)">> $$($$(checkGrammar_3 [|| thename ||]))
<span class="hljs-string" style="color:rgb(221,17,68)">"Hello!"</span>
> $$($$(checkGrammar_3 [|| thename_empty ||]))

<interactive>:<span class="hljs-number" style="color:rgb(0,128,128)">45</span>:<span class="hljs-number" style="color:rgb(0,128,128)">4</span>: error:
    • <span class="hljs-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!important">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-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code class="hljs language-haskell" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline;white-space:pre;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important;display:block;overflow-x:auto;padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248)"><span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">checkGrammar_3</span> :: <span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">Tree</span> a)) -> <span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">Q</span> (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">TExp</span> (<span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">ValidTree</span> a))))
<span class="hljs-title" style="color:rgb(153,0,0);font-weight:bold">useValidTree</span> :: <span class="hljs-type" style="color:rgb(68,85,136);font-weight:bold">ValidTree</span> a -> ...
</code></pre>
<p style="margin:0px 0px 1.2em!important">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:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0"></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">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_-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_-697313513038388539hljs gmail-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_-697313513038388539hljs-pragma" style="color:rgb(153,153,153);font-weight:bold">{-# LANGUAGE TemplateHaskell #-}</span>
<span class="gmail-m_-697313513038388539hljs-import"><span class="gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">import</span> Language.Haskell.TH.Syntax</span>
<span class="gmail-m_-697313513038388539hljs-import"><span class="gmail-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_-697313513038388539hljs-import"><span class="gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">import</span> Language.Haskell.TH.Lift <span class="gmail-m_-697313513038388539hljs-container">()</span></span>

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

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

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

<span class="gmail-m_-697313513038388539hljs-title" style="color:rgb(153,0,0);font-weight:bold">thename_empty</span> :: [<span class="gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Char</span>]
<span class="gmail-m_-697313513038388539hljs-title" style="color:rgb(153,0,0);font-weight:bold">thename_empty</span> = <span class="gmail-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_-697313513038388539hljs gmail-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_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">ExpQ</span>
> :t $($(checkGrammar_2 'thename))
$($(checkGrammar_2 'thename)) :: [<span class="gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Char</span>]
> $($(checkGrammar_2 'thename))
<span class="gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"Hello!"</span>
> $($(checkGrammar_2 'thename_empty))

<interactive>:<span class="gmail-m_-697313513038388539hljs-number" style="color:rgb(0,128,128)">49</span>:<span class="gmail-m_-697313513038388539hljs-number" style="color:rgb(0,128,128)">1</span>: error:
    • <span class="gmail-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_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">CallStack</span> (from <span class="gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">HasCallStack</span>):
  error, called at <interactive>:<span class="gmail-m_-697313513038388539hljs-number" style="color:rgb(0,128,128)">49</span>:<span class="gmail-m_-697313513038388539hljs-number" style="color:rgb(0,128,128)">5</span> <span class="gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">in</span> interactive:<span class="gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Ghci2</span>
      <span class="gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Code</span>: (<span class="gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">if</span> valueFine thename_empty <span class="gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">then</span>
                 varE
                   ((<span class="gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">Name</span> (mkOccName <span class="gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"thename_empty"</span>))
                      (((<span class="gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">NameG</span> <span class="gmail-m_-697313513038388539hljs-type" style="color:rgb(68,85,136);font-weight:bold">VarName</span>) (mkPkgName <span class="gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"main"</span>)) (mkModName <span class="gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"Main"</span>)))
             <span class="gmail-m_-697313513038388539hljs-keyword" style="color:rgb(51,51,51);font-weight:bold">else</span>
                 error <span class="gmail-m_-697313513038388539hljs-string" style="color:rgb(221,17,68)">"value isn't fine"</span>)
    • <span class="gmail-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>