Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/data+is+code?V=26
QUERY_STRINGV=26
CONTENT_TYPE
DOCUMENT_URI/revision/data+is+code
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.69.6.229
REMOTE_PORT56840
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR3.17.28.48
HTTP_CF_RAY87ec1e301b37616a-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_CF_CONNECTING_IP3.17.28.48
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {data is code} (Page\ begun\ by\ \[Lars\ H\],\ 11\ March\ 2007\;\ feel\ free\ to\ expand.)\n\n'''Data\ is\ code'''\ is\ a\ powerful\ programming\ technique\ for\ working\ \nwith\ complicated\ data,\ especially\ tree-like\ data.\ The\ idea\ is\ that\ \nthe\ data\ structure\ itself\ can\ also\ be\ regarded\ as\ a\ command,\ so\ \nthat\ traversing\ a\ data\ structure\ can\ simply\ be\ to\ \[eval\]uate\ it!\ \nBy\ providing\ different\ definitions\ (of\ the\ basic\ node\ types)\ in\ \ndifferent\ \[namespace\]s,\ it\ is\ possible\ to\ implement\ a\ variety\ of\ \ndifferent\ operations\ as\ evaluations\ of\ the\ same\ data\ structure.\n\nThe\ idea\ supports\ \[polymorphism\]\ to\ about\ the\ same\ degree\ as\ \nObject-oriented\ Programming,\ but\ does\ so\ in\ a\ quite\ different\ way.\ \nWhile\ it\ in\ \[OOP\]\ is\ the\ data\ (objects)\ that\ have\ to\ know\ all\ the\ \noperations\ (methods)\ that\ may\ act\ upon\ it,\ data-is-code\ requires\ that\ \nthe\ operations\ (in\ this\ setting:\ namespaces)\ know\ all\ the\ types\ of\ \ndata\ that\ they\ may\ encounter.\ Both\ support\ extensions\ to\ about\ \nthe\ same\ degree:\n\ \ \ *\ In\ OOP,\ a\ new\ type\ can\ be\ implemented\ as\ a\ new\ class,\ whereas\ a\ new\ operation\ can\ be\ implemented\ as\ a\ new\ method\ on\ the\ ancestor\ class.\n\ \ \ *\ With\ data-is-code,\ a\ new\ type\ is\ implemented\ by\ defining\ commands\ for\ it\ in\ all\ operation\ namespaces,\ whereas\ a\ new\ operation\ is\ implemented\ as\ a\ new\ namespace.\nWhere\ OOP\ can\ use\ inheritance\ to\ share\ some\ operation\ definitions\ \n(make\ them\ the\ same\ as\ for\ some\ other\ type),\ data-is-code\ can\ do\ the\ \nsame\ by\ creating\ aliases.\ The\ main\ difference\ is\ that\ objects,\ being\ \ncommands\ even\ in\ cases\ where\ they're\ primarily\ used\ as\ containers\ for\ \ndata,\ need\ to\ be\ explicitly\ destroyed\ and\ therefore\ objects\ add\ the\ \nburden\ of\ lifetime\ management.\ Pure\ data\ that\ is\ sometimes\ treated\ as\ \ncode\ does\ not\ have\ that\ problem.\n\n\[TOOT\]\ is\ a\ bit\ of\ a\ \[data\ is\ code\]/\[OO\]\ hybrid.\ Its\ basic\ mechanism\ is\ to\ treat\ data\ as\ code\ (and\ thus\ doesn't\ have\ the\ lifetime\ management\ problem),\ but\ the\ only\ operation\ implemented\ is\ OO-style\ method\ dispatch.\n----\n**An\ example:\ Algebraic\ expressions**\n\nAn\ example\ which\ illustrates\ many\ of\ these\ points\ can\ be\ provided\ by\ \na\ data\ structure\ for\ simple\ algebraic\ expressions.\ Suppose\ an\ \n''expression''\ is\ a\ list\ on\ one\ of\ the\ forms\n\ \ \ \ :\ \ \ '''+'''\ ''expression''\ ''expression''\n\ \ \ \ :\ \ \ '''-'''\ ''expression''\ ''expression''\n\ \ \ \ :\ \ \ '''*'''\ ''expression''\ ''expression''\n\ \ \ \ :\ \ \ '''/'''\ ''expression''\ ''expression''\n\ \ \ \ :\ \ \ '''var'''\ ''name''\n\ \ \ \ :\ \ \ '''const'''\ ''value''\nWith\ the\ obvious\ interpretation\ of\ +,\ -,\ etc.,\ we\ find\ that\ the\ \nexpression\ (2x-1)/(x+3)\ is\ represented\ by\ the\ data\ structure\n======\n\ \ /\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\n======\n\nSo\ far,\ this\ is\ just\ a\ data\ structure\;\ there\ are\ no\ operations\ which\ \nact\ on\ it.\ (The\ +,\ -,\ and\ friends\ are\ node\ types\ in\ the\ general\ \nterminology\ above.)\ A\ very\ natural\ operation\ would\ however\ be\ to\ \nevaluate\ the\ expression,\ which\ can\ be\ implemented\ as\ follows:\n\n======\n\ \ namespace\ eval\ algexpr::eval\ \{\n\ \ \ \ \ proc\ +\ \{term1\ term2\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$term1\]\ +\ \[eval\ \$term2\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$term1\]\ -\ \[eval\ \$term2\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$factor1\]\ *\ \[eval\ \$factor2\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{numer\ denom\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$numer\]\ /\ double(\[eval\ \$denom\])\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ const\ \{val\}\ \{return\ \$val\}\n\ \ \ \ \ proc\ var\ \{name\}\ \{\n\ \ \ \ \ \ \ \ upvar\ #0\ \$name\ val\n\ \ \ \ \ \ \ \ return\ \$val\n\ \ \ \ \ \}\n\ \ \}\n======\nThe\ command\ to\ actually\ evaluate\ an\ expression\ \$datum\ is\ then\n======\n\ \ namespace\ inscope\ algexpr::eval\ \$datum\n======\n(or\ \[\[namespace\ eval\ algexpr::eval\ \$datum\]\],\ but\ the\ syntax\ of\ \n\[namespace\ inscope\]\ is\ often\ more\ appropriate).\n\n======\n\ \ %\ set\ datum\ \{/\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\n\ \ %\ set\ x\ 1\n\ \ %\ namespace\ inscope\ algexpr::eval\ \$datum\n\ \ 0.25\n\ \ %\ set\ x\ 2\n\ \ %\ namespace\ inscope\ algexpr::eval\ \$datum\n\ \ 0.6\n\ \ %\ set\ x\ 3\n\ \ %\ namespace\ inscope\ algexpr::eval\ \$datum\n\ \ 0.833333333333\n======\n\nWorks\ fine,\ but\ it\ is\ probably\ not\ all\ that\ practical\ to\ fetch\ the\ \nvariable\ values\ from\ global\ variables.\ A\ more\ natural\ construction\ is\ \nto\ provide\ them\ in\ the\ evaluation\ call,\ but\ that\ requires\ a\ different\ \nset\ of\ definitions,\ and\ is\ thus\ a\ different\ operation.\n======\n\ \ namespace\ eval\ algexpr::eval2\ \{\n\ \ \ \ \ proc\ +\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$term1\ \$args\]\ +\ \[eval\ \$term2\ \$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$term1\ \$args\]\ -\ \[eval\ \$term2\ \$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$factor1\ \$args\]\ *\ \[eval\ \$factor2\ \$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{numer\ denom\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$numer\ \$args\]\ /\ double(\[eval\ \$denom\ \$args\])\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ const\ \{val\ args\}\ \{return\ \$val\}\n\ \ \ \ \ proc\ var\ \{name\ args\}\ \{\n\ \ \ \ \ \ \ \ foreach\ \{var\ val\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$name\ eq\ \$var\}\ then\ \{return\ \$val\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ error\ \"No\ value\ specified\ for\ '\$name'\"\n\ \ \ \ \ \}\n\ \ \}\n======Commands\ corresponding\ to\ the\ above\ are\ now\n======\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$datum\ x\ 1\n\ \ 0.25\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$datum\ x\ 2\n\ \ 0.6\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$datum\ x\ 3\n\ \ 0.833333333333\n======\nand\ it's\ not\ much\ harder\ to\ handle\ expressions\ involving\ several\ \nvariables\n======\n\ \ %\ set\ datum2\ \{/\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{var\ y\}\ \{const\ 3\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$datum2\ x\ 1\ y\ 2\n\ \ 0.2\n======\n(Using\ \[namespace\ eval\]\ instead\ would\ require\ \[list\]-quoting\ the\ \nextra\ arguments,\ which\ is\ a\ bit\ artificial.)\n\nEvaluating\ expressions\ is\ a\ rather\ simple\ operation\ however,\ so\ what\ \nabout\ something\ trickier,\ like\ differentiation?\ This\ would\ mean\ that\n======\n\ \ namespace\ inscope\ algexpr::diff\ \$datum\ \$var\n======\nreturns\ the\ derivative\ of\ \$datum\ with\ respect\ to\ \$var.\ The\ basic\ \ndifferentiation\ rules\ are\ straightforward\ to\ implement:\n======\n\ \ namespace\ eval\ algexpr::diff\ \{\n\ \ \ \ \ proc\ +\ \{term1\ term2\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ +\ \[eval\ \$term1\ \[list\ \$var\]\]\ \[eval\ \$term2\ \[list\ \$var\]\]\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ -\ \[eval\ \$term1\ \[list\ \$var\]\]\ \[eval\ \$term2\ \[list\ \$var\]\]\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ +\ \[\n\ \ \ \ \ \ \ \ \ \ \ list\ *\ \[eval\ \$factor1\ \[list\ \$var\]\]\ \$factor2\n\ \ \ \ \ \ \ \ \]\ \[\n\ \ \ \ \ \ \ \ \ \ \ list\ *\ \$factor1\ \[eval\ \$factor2\ \[list\ \$var\]\]\n\ \ \ \ \ \ \ \ \]\n\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{factor1\ factor2\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ /\ \[\n\ \ \ \ \ \ \ \ \ \ \ list\ -\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ *\ \[eval\ \$factor1\ \[list\ \$var\]\]\ \$factor2\n\ \ \ \ \ \ \ \ \ \ \ \]\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ *\ \$factor1\ \[eval\ \$factor2\ \[list\ \$var\]\]\n\ \ \ \ \ \ \ \ \ \ \ \]\n\ \ \ \ \ \ \ \ \]\ \[\n\ \ \ \ \ \ \ \ \ \ \ list\ *\ \$factor2\ \$factor2\n\ \ \ \ \ \ \ \ \]\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ const\ \{val\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ const\ 0\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ var\ \{name\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ const\ \[expr\ \{\$name\ eq\ \$var\}\]\n\ \ \ \ \ \}\n\ \ \}\n======\nSo\ from\ this\ one\ may\ get\n======\n\ \ %\ set\ ddx_datum\ \[namespace\ inscope\ algexpr::diff\ \$datum\ x\]\n\ \ /\ \{-\ \{*\ \{-\ \{+\ \{*\ \{const\ 0\}\ \{var\ x\}\}\ \{*\ \{const\ 2\}\ \{const\ 1\}\}\}\ \{const\ 0\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\ \{*\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{const\ 1\}\ \{const\ 0\}\}\}\}\ \{*\ \{+\ \{var\ x\}\ \{const\ 3\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$ddx_datum\ x\ 2\n\ \ 0.28\n======\nwhich\ fits\ well\ with\ the\ values\ computed\ before.\n\nWhat\ does\ the\ \$ddx_datum\ expression\ look\ like\ in\ more\ traditional\ \nnotation,\ though?\ Conversion\ to\ \[expr\]\ syntax\ is\ of\ course\ another\ \noperation,\ so\ now\ that\ we're\ warmed\ up,\ it\ is\ probably\ easier\ to\ \nimplement\ it\ than\ to\ decipher\ the\ \$ddx_datum\ by\ hand.\ The\ only\ issue\ \none\ needs\ to\ solve\ is\ how\ to\ know\ when\ to\ insert\ parentheses,\ but\ \nthat's\ easily\ handled\ by\ specifying\ the\ operation\ to\ be\ to\n\ \ \ *\ convert\ an\ algexpr\ to\ \[expr\]\ form\ such\ that\ it\ can\ safely\ be\ made\ an\ operand\ of\ an\ expr-operation\ with\ priority\ ''priority'',\ where\ 0\ means\ no\ operation,\ 1\ means\ +,\ 2\ means\ *,\ and\ 3\ is\ as\ denominator.\nThe\ following\ will\ then\ do\ the\ trick\n======\n\ \ namespace\ eval\ algexpr::toexpr\ \{\n\ \ \ \ \ proc\ +\ \{term1\ term2\ priority\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \"\[eval\ \$term1\ \[list\ 1\]\]+\[eval\ \$term2\ \[list\ 1\]\]\"\n\ \ \ \ \ \ \ \ if\ \{\$priority>1\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\$res)\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \$res\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\ priority\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \"\[eval\ \$term1\ \[list\ 1\]\]-\[eval\ \$term2\ \[list\ 2\]\]\"\n\ \ \ \ \ \ \ \ if\ \{\$priority>1\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\$res)\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \$res\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\ priority\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \"\[eval\ \$factor1\ \[list\ 2\]\]*\[eval\ \$factor2\ \[list\ 2\]\]\"\n\ \ \ \ \ \ \ \ if\ \{\$priority>2\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\$res)\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \$res\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{numer\ denom\ priority\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \"\[eval\ \$numer\ \[list\ 2\]\]/\[eval\ \$denom\ \[list\ 3\]\]\"\n\ \ \ \ \ \ \ \ if\ \{\$priority>2\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\$res)\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \$res\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ var\ \{name\ priority\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ -nocase\ --\ \{^\[a-z_\]\[a-z0-9_\]*\$\}\ \$name\]\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \"\\\$\$name\"\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \"\\\[\[list\ set\ \$name\]\\\]\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ const\ \{val\ priority\}\ \{return\ \$val\}\n\ \ \}\n======\nThe\ right\ command\ to\ reformat\ our\ first\ \$datum\ is\ thus\n======\n\ \ %\ namespace\ inscope\ algexpr::toexpr\ \$datum\ 0\n\ \ (2*\$x-1)/(\$x+3)\n======\nWorks\ like\ a\ charm!\ Now\ what\ about\ that\ derivative?\n======\n\ \ %\ namespace\ inscope\ algexpr::toexpr\ \$ddx_datum\ 0\n\ \ ((0*\$x+2*1-0)*(\$x+3)-(2*\$x-1)*(1+0))/((\$x+3)*(\$x+3))\n======\nHmmm...\ It's\ ''correct'',\ but\ not\ very\ nice\ --\ there\ are\ a\ lot\ of\ \nconstant\ subexpressions\ that\ any\ human\ would\ have\ evaluated\ during\ \nthe\ differentiation\ operation.\ One\ way\ to\ get\ rid\ of\ these\ would\ be\ \nto\ improve\ the\ differentiation\ operation\ to\ do\ these\ simplifications\ \non\ the\ fly,\ but\ another\ is\ to\ implement\ a\ more\ generic\ operation\ for\ \n''partial\ evaluation''\ of\ expressions.\ The\ actual\ situations\ one\ has\ \nto\ deal\ with\ are\ the\ same\ in\ both\ cases,\ so\ the\ more\ generic\ \noperation\ seems\ preferable.\n\n======\n\ \ namespace\ eval\ algexpr::parteval\ \{\n\ \ \ \ \ proc\ const\ \{val\ args\}\ \{list\ const\ \$val\}\n\ \ \ \ \ proc\ var\ \{name\ args\}\ \{\n\ \ \ \ \ \ \ \ foreach\ \{var\ val\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$name\ eq\ \$var\}\ then\ \{return\ \[list\ const\ \$val\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ var\ \$name\]\n\ \ \ \ \ \}\n\ \ \ \ \ #\ These\ two\ were\ the\ central\ ones,\ but\ most\ of\ the\ actual\ \n\ \ \ \ \ #\ work\ remains,\ since\ there\ are\ many\ small\ cases\ where\n\ \ \ \ \ #\ partial\ evaluation\ is\ possible.\n\ \ \ \ \ proc\ +\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ res1\ \[eval\ \$term1\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t1\ v1\}\ \$res1\ break\n\ \ \ \ \ \ \ \ set\ res2\ \[eval\ \$term2\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t2\ v2\}\ \$res2\ break\n\ \ \ \ \ \ \ \ if\ \{\$t1\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$t2\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ \[expr\ \{\$v1\ +\ \$v2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$v1==0\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ res2\n\ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ +\ \$res2\ \$res1\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$t2\ eq\ \"const\"\ &&\ \$v2==0\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ res1\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ +\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ res1\ \[eval\ \$term1\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t1\ v1\}\ \$res1\ break\n\ \ \ \ \ \ \ \ set\ res2\ \[eval\ \$term2\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t2\ v2\}\ \$res2\ break\n\ \ \ \ \ \ \ \ if\ \{\$t1\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$t2\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ \[expr\ \{\$v1\ -\ \$v2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ -\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$t2\ eq\ \"const\"\ &&\ \$v2==0\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ res1\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ -\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ res1\ \[eval\ \$factor1\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t1\ v1\}\ \$res1\ break\n\ \ \ \ \ \ \ \ set\ res2\ \[eval\ \$factor2\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t2\ v2\}\ \$res2\ break\n\ \ \ \ \ \ \ \ if\ \{\$t1\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$t2\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ \[expr\ \{\$v1\ *\ \$v2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$v1==0\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ 0\n\ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$v1==1\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ res2\n\ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ *\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$t2\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$v2==0\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ 0\n\ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$v2==1\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ res1\n\ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ *\ \$res2\ \$res1\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ *\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{numer\ denom\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ res1\ \[eval\ \$numer\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t1\ v1\}\ \$res1\ break\n\ \ \ \ \ \ \ \ set\ res2\ \[eval\ \$denom\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t2\ v2\}\ \$res2\ break\n\ \ \ \ \ \ \ \ if\ \{\$t2\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$t1\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ \[expr\ \{\$v1\ /\ double(\$v2)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$v2==1\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ res1\n\ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ /\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ /\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \}\n======\n\nSome\ examples:\n======\n\ \ %\ namespace\ inscope\ algexpr::parteval\ \$datum\ x\ 2\n\ \ const\ 0.6\n\ \ %\ namespace\ inscope\ algexpr::parteval\ \$datum2\ x\ 2\n\ \ /\ \{const\ 3\}\ \{+\ \{var\ y\}\ \{const\ 3\}\}\n======\nSo,\ what\ about\ that\ ugly\ derivative?\n======\n\ \ %\ set\ ddx_datum_simplified\ \[namespace\ inscope\ algexpr::parteval\ \$ddx_datum\]\n\ \ /\ \{-\ \{*\ \{const\ 2\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\}\ \{*\ \{+\ \{var\ x\}\ \{const\ 3\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::toexpr\ \$ddx_datum_simplified\ 0\n\ \ (2*(\$x+3)-(2*\$x-1))/((\$x+3)*(\$x+3))\n======\nBetter,\ but\ still\ redundant.\ (Simplifying\ algebraic\ expressions\ to\ \nabout\ the\ degree\ expected\ from\ a\ math\ student\ is\ really\ rather\ \ncomplicated,\ once\ you\ have\ to\ instruct\ a\ computer\ to\ do\ it,\ and\ this\ \nrepresentation\ with\ binary\ +,\ -,\ *,\ and\ /\ is\ not\ very\ practical\ for\ \nthe\ task.\ Better\ solutions\ are\ beyond\ the\ simple\ example,\ however.)\n\nLet\ us\ instead\ consider\ how\ to\ extend\ the\ algexpr\ data\ structure\ with\ \na\ new\ node\ type,\ say\ '''exp'''\ for\ the\ (natural\ base)\ exponential\ \nfunction.\ This\ requires\ defining\ exp\ procedures\ in\ all\ the\ namespaces\ \nwhere\ this\ node\ type\ may\ be\ expected:\n======\n\ \ namespace\ eval\ algexpr::eval\ \{\n\ \ \ \ \ proc\ exp\ \{arg\}\ \{expr\ \{exp(\[eval\ \$arg\])\}\}\n\ \ \}\n\ \ namespace\ eval\ algexpr::eval2\ \{\n\ \ \ \ \ proc\ exp\ \{arg\ args\}\ \{expr\ \{exp(\[eval\ \$arg\ \$args\])\}\}\n\ \ \}\n\ \ namespace\ eval\ algexpr::diff\ \{\n\ \ \ \ \ proc\ exp\ \{arg\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ *\ \[list\ exp\ \$arg\]\ \[eval\ \$arg\ \[list\ \$var\]\]\n\ \ \ \ \ \}\n\ \ \}\n\ \ namespace\ eval\ algexpr::toexpr\ \{\n\ \ \ \ \ proc\ exp\ \{arg\ priority\}\ \{return\ \"exp(\[eval\ \$arg\ \[list\ 0\]\])\"\}\n\ \ \}\n\ \ namespace\ eval\ algexpr::parteval\ \{\n\ \ \ \ \ proc\ exp\ \{arg\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ ares\ \[eval\ \$arg\ \$args\]\n\ \ \ \ \ \ \ \ if\ \{\[lindex\ \$ares\ 0\]\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ const\ \[expr\ \{exp(\[lindex\ \$ares\ 1\])\}\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ exp\ \$ares\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \}\n======\nThat's\ all\ there\ is\ to\ it:\n======\n\ \ %\ set\ datum3\ \{exp\ \{/\ \{var\ x\}\ \{var\ y\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$datum3\ x\ 2\ y\ 1\n\ \ 7.38905609893\n\ \ %\ set\ ddy_datum3\ \[namespace\ inscope\ algexpr::diff\ \$datum3\ y\]\n\ \ *\ \{exp\ \{/\ \{var\ x\}\ \{var\ y\}\}\}\ \{/\ \{-\ \{*\ \{const\ 0\}\ \{var\ y\}\}\ \{*\ \{var\ x\}\ \{const\ 1\}\}\}\ \{*\ \{var\ y\}\ \{var\ y\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::toexpr\ \$ddy_datum3\ 0\n\ \ exp(\$x/\$y)*(0*\$y-\$x*1)/(\$y*\$y)\n\ \ %\ set\ ddy_datum3\ \[namespace\ inscope\ algexpr::parteval\ \$ddy_datum3\]\n\ \ *\ \{exp\ \{/\ \{var\ x\}\ \{var\ y\}\}\}\ \{/\ \{-\ \{const\ 0\}\ \{var\ x\}\}\ \{*\ \{var\ y\}\ \{var\ y\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::toexpr\ \$ddy_datum3\ 0\n\ \ exp(\$x/\$y)*(0-\$x)/(\$y*\$y)\n======\n\n----\n**Sharing\ commands**\n\nThe\ examples\ above\ never\ gave\ an\ opportunity\ to\ use\ the\ same\ command\ \nfor\ more\ than\ one\ thing,\ but\ using\ \[interp\ alias\]\ or\ \[namespace\ import\]\ \nto\ make\ one\ command\ appear\ in\ several\ places\ is\ a\ standard\ Tcl\ \nprogramming\ technique\ that\ is\ explained\ elsewhere.\ There\ are\ however\ \nsome\ special\ issues\ one\ should\ take\ note\ of:\n\n\ \ \ Avoid\ colons\ in\ node\ types:\ \ \ Colons\ interact\ strangely\ with\ the\ namespace\ separator\ ::,\ so\ you\ may\ be\ unable\ to\ make\ use\ of,\ or\ even\ speak\ about,\ the\ command\ you\ want.\n\n\ \ \ Be\ aware\ of\ the\ namespace\ context:\ \ \ If\ you\ import\ or\ alias\ a\ proc\ into\ a\ namespace,\ then\ the\ namespace\ context\ of\ this\ proc\ does\ ''not''\ follow.\ For\ set-ups\ such\ as\ the\ above,\ where\ the\ namespace\ context\ is\ an\ essential\ foundation\ for\ the\ interpretation,\ this\ can\ be\ disastrous.\n\nThere\ is\ a\ rather\ simple\ solution\ to\ the\ namespace\ problem,\ however:\ \nuse\ \[uplevel\]\ instead\ of\ \[eval\]!\ This\ works\ because\ it\ causes\ a\ child\ \nnode\ to\ be\ interpreted\ as\ a\ command\ in\ the\ same\ context\ as\ the\ parent\ \nnode\ was,\ so\ if\ for\ example\ the\ child\ and\ parent\ nodes\ are\ of\ the\ \nsame\ type\ then\ they\ will\ both\ be\ handled\ by\ the\ same\ command.\ \n\nIf\ this\ still\ seem\ mysterious\ to\ you,\ then\ remember\ that\ \n\[namespace\ eval\]\ and\ kin\ (e.g.\ \[namespace\ inscope\])\ adds\ a\ level\ \nvisible\ to\ \[uplevel\].\ The\ following\ provides\ an\ example:\n======\n\ \ namespace\ eval\ ::foo\ \{\}\n\ \ proc\ ::a\ \{\}\ \{\n\ \ \ \ \ puts\ \"-\ I'm\ ::a,\ called\ as\ \[info\ level\ 0\].\"\n\ \ \ \ \ return\ ::a\n\ \ \}\n\ \ proc\ ::foo::a\ \{\}\ \{\n\ \ \ \ \ puts\ \"-\ I'm\ ::foo::a,\ called\ as\ \[info\ level\ 0\].\"\n\ \ \ \ \ return\ ::foo::a\n\ \ \}\n\ \ proc\ ::b\ \{\}\ \{\n\ \ \ \ \ puts\ -nonewline\ \"-\ I'm\ ::b,\ called\ as\ \[info\ level\ 0\]\;\ \"\n\ \ \ \ \ puts\ \"my\ namespace\ is\ \[namespace\ current\].\"\n\ \ \ \ \ puts\ \"::b\ says:\ I've\ just\ called\ \[uplevel\ 1\ a\].\"\n\ \ \}\n\ \ interp\ alias\ \{\}\ ::foo::b\ \{\}\ ::b\n======\nThe\ call\ \[\[b\]\]\ prints\n\ \ -\ I'm\ ::b,\ called\ as\ b\;\ my\ namespace\ is\ ::.\n\ \ -\ I'm\ ::a,\ called\ as\ a.\n\ \ ::b\ says:\ I've\ just\ called\ ::a.\nand\ the\ call\ \[\[namespace\ inscope\ foo\ b\]\]\ prints\n\ \ -\ I'm\ ::b,\ called\ as\ ::b\;\ my\ namespace\ is\ ::.\n\ \ -\ I'm\ ::foo::a,\ called\ as\ a.\n\ \ ::b\ says:\ I've\ just\ called\ ::foo::a.\nbecause\ '''b'''\ calls\ the\ '''a'''\ visible\ in\ the\ namespace\ from\ which\ \n'''b'''\ itself\ was\ called,\ even\ if\ that\ isn't\ where\ '''b'''\ resides.\n\nAn\ alternative\ approach\ to\ the\ namespace\ problem,\ which\ can\ be\ useful\ \nfor\ generic\ utility\ commands\ (that\ via\ aliases\ with\ some\ extra\ \narguments\ can\ implement\ a\ whole\ score\ of\ commands),\ is\ to\ supply\ the\ \nintended\ namespace\ as\ an\ extra\ argument.\ Then\ if\ one\ defines\n======\n\ \ proc\ exprbinop\ \{ns\ op\ left\ right\ args\}\ \{\n\ \ \ \ \ set\ leftval\ \[namespace\ eval\ \$ns\ \$left\ \$args\]\n\ \ \ \ \ set\ rightval\ \[namespace\ eval\ \$ns\ \$right\ \$args\]\n\ \ \ \ \ expr\ \\\$leftval\ \$op\ \\\$rightval\n\ \ \}\n======\nthe\ algexpr::eval\ and\ algexpr::eval2\ implementations\ of\ +,\ -,\ and\ *\ \ncan\ all\ be\ given\ as\ aliases\ to\ this\ exprbinop:\n======\n\ \ interp\ alias\ \{\}\ algexpr::eval::+\ \{\}\ exprbinop\ algexpr::eval\ +\n\ \ interp\ alias\ \{\}\ algexpr::eval::-\ \{\}\ exprbinop\ algexpr::eval\ -\n\ \ interp\ alias\ \{\}\ algexpr::eval::*\ \{\}\ exprbinop\ algexpr::eval\ *\n\ \ interp\ alias\ \{\}\ algexpr::eval2::+\ \{\}\ exprbinop\ algexpr::eval2\ +\n\ \ interp\ alias\ \{\}\ algexpr::eval2::-\ \{\}\ exprbinop\ algexpr::eval2\ -\n\ \ interp\ alias\ \{\}\ algexpr::eval2::*\ \{\}\ exprbinop\ algexpr::eval2\ *\n======\nUsing\ \[uplevel\]\ is\ however\ an\ easier\ solution,\ as\ long\ as\ one\ can\ \npredict\ what\ level\ to\ uplevel\ to.\n\n----\n**Handling\ unknown\ node\ types**\n\nIn\ some\ cases,\ the\ set\ of\ possible\ node\ types\ is\ not\ known\ from\ start,\ but\ all\ except\ a\ known\ set\ of\ nodes\ are\ to\ be\ given\ default\ processing\ (which\ is\ typically\ to\ do\ nothing\ here,\ but\ recursively\ process\ all\ the\ children).\ This\ is\ a\ problem\ for\ the\ \[namespace\ inscope\]\ technique,\ since\ there\ is\ no\ way\ to\ stop\ Tcl\ from\ looking\ outside\ the\ namespace\ \ for\ command\ definitions:\ \[namespace\ path\]\ can\ be\ used\ to\ make\ Tcl\ look\ in\ additional\ namespaces,\ and\ \[namespace\ unknown\]\ can\ be\ used\ to\ override\ the\ generic\ \[unknown\],\ but\ there\ is\ no\ way\ to\ prevent\ commands\ in\ the\ ::\ namespace\ from\ being\ found\ as\ legitimate\ implementations\ of\ a\ the\ operation\ on\ a\ node.\ If\ \[list\],\ \[set\],\ \[expr\],\ or\ the\ like\ can\ occur\ as\ node\ types\ then\ this\ means\ you're\ in\ trouble.\n\nOne\ way\ to\ get\ around\ this\ could\ be\ to\ make\ sure\ that\ the\ ::\ namespace\ is\ empty,\ by\ using\ an\ \[empty\ interpreter\]\ like\ so:\n======\n\ \ interp\ create\ -safe\ dispatch\n\ \ dispatch\ hide\ namespace\n\ \ dispatch\ invokehidden\ namespace\ delete\ ::\n======\nafter\ which\ you\ can\ create\ your\ node\ types\ as\ aliases\ from\ dispatch\ to\ your\ main\ interpreter,\ and\ process\ a\ node\ by\ doing\n\ \ \ \ :\ \ \ '''dispatch\ invokehidden\ namespace\ inscope'''\ ''namespace''\ ''node''\ ?''arg''\ ...?\nbut\ this\ is\ rather\ complicated.\n\nAs\ of\ Tcl\ 8.5,\ a\ better\ approach\ is\ to\ use\ an\ ensemble\ to\ do\ the\ dispatch,\ since\ this\ does\ not\ look\ outside\ its\ given\ namespace.\ The\ set-up\ closest\ to\ that\ of\ \[namespace\ inscope\]\ is\ to\ do\n======\n\ \ namespace\ eval\ \$operation\ \{\n\ \ \ \ \ \ namespace\ export\ *\n\ \ \ \ \ \ namespace\ ensemble\ create\ -prefix\ 0\n\ \ \}\n======\nafter\ which\ the\ counterpart\ of\n======\n\ \ namespace\ inscope\ \$operation\ \$node\ \$arg\n======\nis\n======\n\ \ \$operation\ \{*\}\$node\ \$arg\n======\ne.g.\n======\n\ \ algexpr::eval2\ \{*\}\$datum\ x\ 1\n======\ninstead\ of\n======\n\ \ namespace\ inscope\ algexpr::eval2\ \$datum\ x\ 1\n======\nThis\ will\ throw\ an\ error\ when\ the\ node\ type\ is\ unknown\;\ to\ do\ something\ else\ one\ must\ supply\ an\ '''-unknown'''\ handler\ for\ the\ ensemble.\n\nA\ problem\ with\ this\ set-up\ is\ however\ that\ it\ is\ less\ obvious\ how\ to\ make\ recursive\ calls\ for\ children\;\ an\ \[eval\]\ or\ \[uplevel\]\ on\ a\ child\ will\ not\ reinvoke\ the\ ensemble\ (thus\ losing\ the\ protection\ against\ unknown\ node\ types).\ Hardcoding\ the\ fully\ qualified\ name\ of\ the\ ensemble\ where\ one\ needs\ to\ make\ a\ recursive\ call\ is\ one\ option,\ but\ that\ gets\ inconvenient\ for\ nested\ namespaces.\ When\ the\ ensemble\ (as\ is\ the\ default)\ has\ the\ same\ name\ as\ its\ namespace,\ its\ name\ can\ be\ obtained\ as\ \[\[namespace\ current\]\],\ e.g.\n======\n\ \ \ \ \ proc\ +\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[\[namespace\ current\]\ \{*\}\$term1\ \{*\}\$args\]\ +\ \[\[namespace\ current\]\ \{*\}\$term2\ \{*\}\$args\]\}\n\ \ \ \ \ \}\n======\nbut\ this\ is\ prolix\ too,\ and\ leads\ to\ \[shimmering\]\ (command\ look-up\ cannot\ be\ cached,\ as\ the\ name\ is\ regenerated\ whenever\ it\ is\ used).\ A\ better\ approach\ is\ often\ to\ place\ the\ ensemble\ command\ ''inside''\ its\ own\ namespace,\ as\ this\ makes\ it\ callable\ without\ namespace\ qualification.\ Using\ the\ empty\ string\ as\ name\ of\ the\ ensemble\ command,\ this\ can\ look\ as\ follows:\n\n======\n\ \ namespace\ eval\ algexpr::eval2\ \{\n\ \ \ \ \ proc\ +\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[\"\"\ \{*\}\$term1\ \{*\}\$args\]\ +\ \[\"\"\ \{*\}\$term2\ \{*\}\$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[\"\"\ \{*\}\$term1\ \{*\}\$args\]\ -\ \[\"\"\ \{*\}\$term2\ \{*\}\$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[\"\"\ \{*\}\$factor1\ \{*\}\$args\]\ *\ \[\"\"\ \{*\}\$factor2\ \{*\}\$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{numer\ denom\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[\"\"\ \{*\}\$numer\ \{*\}\$args\]\ /\ double(\[\"\"\ \{*\}\$denom\ \{*\}\$args\])\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ const\ \{val\ args\}\ \{return\ \$val\}\n\ \ \ \ \ proc\ var\ \{name\ args\}\ \{\n\ \ \ \ \ \ \ \ foreach\ \{var\ val\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$name\ eq\ \$var\}\ then\ \{return\ \$val\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ error\ \"No\ value\ specified\ for\ '\$name'\"\n\ \ \ \ \ \}\n\ \ \ \ \ namespace\ export\ ?*\n\ \ \ \ \ namespace\ ensemble\ create\ -command\ \[namespace\ current\]::\ \\\n\ \ \ \ \ \ \ \ -prefix\ 0\ -unknown\ \[list\ ::default_to_type\ +\]\n\ \ \ \ \ interp\ alias\ \{\}\ \[namespace\ current\]\ \{\}\ \[namespace\ current\]::\n\ \ \}\n\ \ proc\ default_to_type\ \{type\ ensemble\ args\}\ \{list\ \$ensemble\ \$type\}\n======\n\nThe\ \[interp\ alias\]\ is\ so\ that\ the\ ensemble\ can\ still\ be\ called\ by\ external\ users\ as\ if\ it\ had\ the\ same\ name\ as\ its\ namespace.\ Using\ ?*\ as\ export\ pattern\ means\ all\ commands\ in\ the\ namespace\ ''except''\ the\ ensemble\ command\ itself\ are\ available\ as\ node\ types.\ The\ '''-unknown'''\ handler\ means\ all\ unknown\ node\ types\ are\ treated\ as\ if\ they\ were\ '''+''':\n======\n\ \ %\ algexpr::eval2\ +\ \{const\ 1\}\ \{var\ x\}\ x\ 2\n\ \ 3\n\ \ %\ algexpr::eval2\ -\ \{const\ 1\}\ \{var\ x\}\ x\ 2\n\ \ -1\n\ \ %\ algexpr::eval2\ /\ \{const\ 1\}\ \{var\ x\}\ x\ 2\n\ \ 0.5\n\ \ %\ algexpr::eval2\ &\ \{const\ 1\}\ \{var\ x\}\ x\ 2\n\ \ 3\n======\n\n----\n**Traversals\ with\ state**\n\nSometimes,\ it\ is\ important\ to\ maintain\ a\ state\ when\ traversing\ a\ data\ \nstructure,\ and\ update\ that\ state\ for\ each\ node\ processed.\ That\ each\ \nnode\ is\ processed\ in\ a\ separate\ local\ context\ makes\ it\ trickier\ to\ \nmaintain\ such\ a\ state\ than\ it\ would\ be\ if\ a\ single\ procedure\ call\ did\ \nall\ the\ work,\ but\ there\ are\ some\ approaches\ one\ can\ use:\n\ \ \ 1.\ Use\ a\ global\ or\ namespace\ variable.\ Inelegant,\ but\ often\ easy\ and\ good\ enough.\n\ \ \ 2.\ Use\ a\ local\ variable\ that\ is\ accessed\ using\ \[upvar\].\ Gets\ into\ trouble\ if\ \[uplevel\]\ or\ \[namespace\ eval\]\ is\ being\ used\ as\ shown\ in\ the\ previous\ section.\n\ \ \ 3.\ Pass\ the\ previous\ state\ as\ a\ command\ argument\ and\ return\ it\ as\ the\ command\ result.\ This\ is\ the\ \[functional\ programming\]\ idiom.\n----\n**Collecting\ children\ in\ a\ sublist\ or\ placing\ them\ directly\ the\ node\ list**\n\nThe\ data\ in\ a\ node\ can\ be\ categorised\ as:\n\ \ \ 1.\ Node\ type.\n\ \ \ 2.\ Annotations\ (data\ not\ in\ the\ form\ of\ a\ node).\n\ \ \ 3.\ Children\ (data\ in\ node\ format).\nIn\ the\ algebraic\ examples\ above,\ the\ '''const'''\ and\ '''var'''\ nodes\ have\ \nannotations\ (value\ and\ variable\ names\ respectively)\ but\ no\ children,\ \nwhereas\ the\ other\ node\ types\ have\ children\ but\ no\ annotations.\nThe\ \[grammar_fa\]\ example\ (see\ bullet\ list\ below)\ is\ similar,\ \nbut\ adds\ the\ complication\ that\ some\ nodes\ can\ have\ an\ \narbitrary\ number\ of\ children.\ In\ the\ \[parsetcl\]\ example,\ \nall\ nodes\ have\ two\ pieces\ of\ annotation\ and\ in\ addition\ many\nhave\ a\ variable\ number\ of\ children.\ Most\ general\ is\ the\ data\ \nstructure\ employed\ by\ \[a\ little\ XML\ parser\],\ since\ a\ typical\ \nnode\ in\ that\ case\ can\ have\ an\ arbitrary\ number\ of\ annotations\ \nand\ an\ arbitrary\ number\ of\ children.\n\nThe\ issue\ considered\ here\ is\ how\ to\ best\ design\ the\ list\ \nstructure\ for\ the\ various\ node\ types.\ If\ the\ number\ of\ \nannotations\ and\ children\ is\ determined\ by\ the\ node\ type,\ then\ \nit\ probably\ seems\ natural\ to\ just\ lay\ them\ out\ in\ a\ flat\ \nstructure\n======\n\ \ nodetype\ annot1\ annot2\ ...\ annotM\ child1\ child2\ ...\ childN\n======\nsince\ it\ is\ then\ trivial\ to\ name\ all\ the\ arguments\ in\ the\ \nproc\ definition\ \n======\n\ \ proc\ \$nodetype\ \{annot1\ annot2\ ...\ annotM\ child1\ child2\ ...\ childN\}\ \{\ #\ ...\n======\n--\ no\ need\ to\ \[lassign\]\ or\ such,\ and\ you\ get\ good\ error\ \nmessages\ for\ free.\n\nIt\ is\ ''possible''\ to\ use\ this\ design\ also\ for\ node\ types\ with\ \na\ variable\ number\ of\ children,\ since\ the\ proc\ definition\ can\ \njust\ as\ easily\ be\n======\n\ \ proc\ \$nodetype\ \{annot1\ annot2\ ...\ annotN\ args\}\ \{\ #\ ...\n======\n(this\ was\ very\ much\ done\ in\ \[parsetcl\]),\ but\ in\ these\ cases\ \nit\ is\ ''better''\ to\ have\ just\ one\ argument\ which\ is\ the\ list\ \nof\ children,\ like\ so:\n======\n\ \ proc\ \$nodetype\ \{annot1\ annot2\ ...\ annotN\ children\}\ \{\ #\ ...\n======\nWhy\ is\ that?\ Because\ it\ simplifies\ operations\ which\ take\ \narguments\ (like\ '''eval2''',\ '''parteval''',\ '''diff''',\ and\ \n'''toexpr'''\ above)!\ Consider\ what\ would\ happen\ if\ +\ nodes\ \nlooked\ like\n\ \ \ \ :\ \ \ '''+'''\ ''?term\ ...?''\n(variadic\ addition\ is\ actually\ more\ natural\ for\ algebra).\ \nThe\ '''eval'''\ operation\ is\ straightforward\n======\n\ \ proc\ algexpr::eval::+\ \{args\}\ \{\n\ \ \ \ \ set\ sum\ 0\n\ \ \ \ \ foreach\ term\ \$args\ \{\n\ \ \ \ \ \ \ \ set\ sum\ \[expr\ \{\$sum\ +\ \[eval\ \$term\]\}\]\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$sum\n\ \ \}\n======\nbut\ the\ '''diff'''\ operation\ is\ much\ trickier\ due\ to\ the\ \nexceptional\ final\ argument\ holding\ the\ differentiation\ \nvariable\ name\n======\n\ \ proc\ algexpr::diff::+\ \{args\}\ \{\n\ \ \ \ \ set\ var\ \[lindex\ \$args\ end\]\n\ \ \ \ \ set\ res\ \[list\ +\]\n\ \ \ \ \ foreach\ term\ \[lrange\ \$args\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ lappend\ res\ \[eval\ \$term\ \[list\ \$var\]\]\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$res\n\ \ \}\n======\nand\ the\ '''eval2'''\ operation\ is\ simply\ impossible\ --\ there\ \nis\ no\ sure\ way\ to\ distinguish\ variable-value\ arguments\ from\ \nchild\ node\ arguments.\n\nThis\ problem\ does\ not\ arise\ if\ the\ syntax\ had\ instead\ been\ \n\ \ \ \ :\ \ \ '''sum'''\ ''term-list''\n(the\ '''+'''\ node\ type\ is\ already\ assigned\ to\ binary\ addition)\ since\ \nthe\ implementations\ are\ then\ \n======\n\ \ proc\ algexpr::diff::sum\ \{terms\ var\}\ \{\n\ \ \ \ \ set\ res\ \[list\ sum\]\n\ \ \ \ \ foreach\ term\ \$terms\ \{\n\ \ \ \ \ \ \ \ lappend\ res\ \[eval\ \$term\ \[list\ \$var\]\]\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$res\n\ \ \}\n\ \ proc\ algexpr::eval2::sum\ \{terms\ args\}\ \{\n\ \ \ \ \ set\ sum\ 0\n\ \ \ \ \ foreach\ term\ \$terms\ \{\n\ \ \ \ \ \ \ \ set\ sum\ \[expr\ \{\$sum\ +\ \[eval\ \$term\ \$args\]\}\]\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$sum\n\ \ \}\n======\n\[A\ little\ XML\ parser\]\ has\ got\ this\ right,\ with\ one\ argument\ \nthat\ is\ a\ dictionary\ of\ annotations\ and\ another\ that\ is\ the\ \nlist\ of\ children.\ After\ that\ can\ follow\ any\ number\ of\ operation\ \narguments,\ and\ it\ is\ easy\ to\ see\ which\ is\ which.\n\nStill,\ it\ sometimes\ happens\ that\ one\ has\ to\ implement\ operations\ \non\ data\ in\ a\ legacy\ format,\ with\ the\ list\ of\ children\ expanded\ \ninto\ the\ node\ list.\ What\ can\ one\ do\ then?\ One\ possibility\ is\ to\ \nfirst\ implement\ an\ operation\ converting\ the\ data\ to\ a\ child-list\ \nformat,\ because\ that\ operation\ doesn't\ need\ arguments,\ and\ then\ \nperform\ the\ wanted\ operation\ on\ the\ converted\ data.\ Another\ \npossibility\ is\ to\ design\ the\ argument\ structure\ for\ the\ operation\ \nso\ that\ there\ is\ an\ explicit\ end-of-children\ argument,\ like\ --\ \nto\ signal\ end\ of\ switches.\ In\ this\ case,\ the\ right\ form\ of\ an\ \nend-of-children\ argument\ is\ an\ empty\ list,\ since\ every\ child\ \nmust\ be\ a\ list\ of\ length\ at\ least\ 1.\ In\ that\ case,\ one\ could\ \ndefine\n======\n\ \ proc\ algexpr::eval3::+\ \{args\}\ \{\n\ \ \ \ \ set\ n\ 0\n\ \ \ \ \ foreach\ term\ \$args\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$term\]\ <\ 1\}\ then\ \{break\}\n\ \ \ \ \ \ \ \ incr\ n\n\ \ \ \ \ \}\n\ \ \ \ \ set\ sum\ 0\n\ \ \ \ \ foreach\ term\ \[lreplace\ \$args\ \$n\ end\]\ \{\n\ \ \ \ \ \ \ \ set\ sum\ \[expr\ \{\$sum\ +\ \[eval\ \$term\ \[lrange\ \$args\ \$n\ end\]\]\}\]\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$sum\n\ \ \}\n======\nand\ make\ calls\ like\n======\n\ \ namespace\ inscope\ algexpr::eval3\ \$datum\ \{\}\ x\ 1\n======\nbut\ the\ need\ for\ the\ extra\ end-of-children\ argument\ means\ this\ \nis\ not\ the\ same\ operation\ as\ '''eval2'''.\n\n----\n**Discussion**\n\n\[male\]\ -\ 2007-03-12:\n\nThanks\ for\ your\ very\ detailed\ \[data\ is\ code\]\ page!\n\nMy\ best\ example\ for\ \[data\ is\ code\]\ was\ my\ way\ to\ read\ VRML\ files,\ to\ import\ their\ structure\ and\ their\ geometrical\ data:\n\n\ \ \ 1.\ Read\ the\ file\ data\n\ \ \ 2.\ Convert\ the\ file\ data\ to\ a\ valid\ list\n\ \ \ 3.\ Reorganize\ the\ file\ data\ list\ to\ have\ all\ VRML\ node\ attributes\ in\ sub\ lists\n\ \ \ 4.\ Evaluate\ this\ list\ with\ the\ scheme,\ that\ each\ VRML\ node\ name\ could\ be\ the\ name\ of\ a\ tcl\ command\ or\ procedure.\ If\ such\ a\ tcl\ procedure\ exists,\ than\ evaluate\ it\ with\ the\ VRML\ node\ attributes\ as\ arguments,\ if\ not\ ignore\ this\ VRML\ node.\n\nSuch\ becomes\ VRML\ data\ executable\ code.\n\n----\n\[NEM\]\ ''12\ Mar\ 2007'':\ Thanks,\ Lars,\ this\ is\ a\ useful\ technique\ to\ document.\ I've\ only\ skimmed\ at\npresent,\ so\ apologies\ if\ some\ of\ these\ remarks\ are\ covered.\ An\ alternative\ to\ using\ a\ namespace\nwould\ be\ to\ just\ use\ a\ \[switch\]\ (or\ some\ form\ of\ \[pattern\ matching\])\ inside\ a\ proc.\ For\ instance,\nthe\ first\ expression\ evaluator\ might\ be\ written:\n======\n\ proc\ algexpr::calc\ expr\ \{\ \ \ \ \ \ \ \ \ \n\ \ \ \ lassign\ \$expr\ op\ a\ b\n\ \ \ \ switch\ -exact\ --\ \$op\ \{\n\ \ \ \ \ \ \ \ +\ \ \ \ \ \{\ expr\ \{\[calc\ \$a\]\ +\ \[calc\ \$b\]\}\ \}\n\ \ \ \ \ \ \ \ -\ \ \ \ \ \{\ expr\ \{\[calc\ \$a\]\ -\ \[calc\ \$b\]\}\ \}\n\ \ \ \ \ \ \ \ *\ \ \ \ \ \{\ expr\ \{\[calc\ \$a\]\ *\ \[calc\ \$b\]\}\ \}\n\ \ \ \ \ \ \ \ /\ \ \ \ \ \{\ expr\ \{\[calc\ \$a\]\ /\ double(\[calc\ \$b\])\}\ \}\n\ \ \ \ \ \ \ \ const\ \{\ return\ \$a\ \}\n\ \ \ \ \ \ \ \ var\ \ \ \{\ upvar\ #0\ \$a\ v\;\ return\ \$v\ \}\n\ \ \ \ \}\ \ \ \ \ \n\ \}\n======\nA\ sugared\ version\ of\ this\ appears\ in\ \[a\ lambda\ calculus\ interpreter\ with\ arithmetic\].\n\n''\[Lars\ H\]:\ The\ only\ catch\ in\ that\ is\ that\ it\ doesn't\ really\ do\ \[data\ is\ code\],\ as\ the\ data\ isn't\ treated\ as\ code\;\ in\ a\ sense,\ it\ is\ precisely\ the\ more\ traditional\ technique\ that\ data-is-code\ provides\ an\ alternative\ to!''\n\n\[NEM\]:\ Right,\ but\ what\ are\ the\ advantages\ of\ manipulating\ data\ as\ Tcl\ code\ as\ opposed\ to\ just\ntreating\ it\ as\ a\ bit\ of\ data?\ Speed?\ Leveraging\ the\ existing\ Tcl\ interpreter\ code?\ The\ above\nproc\ is\ a\ bare-bones\ interpreter\ for\ a\ minimal\ language\ of\ arithmetic\ expressions,\ so\ its\ data\nis\ also\ code.\ Code\ ''is''\ just\ data,\ after\ all.\ (The\ \"real\"\ dichotomy\ would\ be\ between\ data\ and\nprocesses,\ where\ code\ could\ be\ seen\ as\ data\ that\ describes\ a\ process).\n\n\[Lars\ H\]:\ Speed\ and\ leveraging\ existing\ mechanisms\ are\ indeed\ reasons\ why\ this\ is\ useful.\ Another\ reason\ is\ extensionality\ (how\ do\ you\ tell\ algexpr::calc\ about\ the\ '''exp'''\ node\ type?).\ As\ for\ \"\[code\ is\ data\]\"...\ well,\ that\ would\ be\ the\ subject\ of\ another\ page\ (every\ now\ and\ then\ I\ mix\ the\ two\ up\ too).\n\n\[NEM\]:\ Code\ really\ is\ just\ data...\ But\ anyway,\ to\ the\ other\ points:\ I'm\ not\ so\ sure\ about\ the\nspeed,\ although\ I'm\ prepared\ to\ believe\ it\ for\ more\ complex\ examples.\ For\ example,\ transforming\nXML\ data\ into\ Tcl\ code\ could\ result\ in\ a\ quite\ fast\ parser,\ but\ it's\ tricky\ to\ do\ correctly,\ and\nthere\ are\ of\ course\ issues\ with\ trust\ --\ Tcl\ is\ a\ much\ more\ powerful\ language\ than\ a\ custom\nlittle\ interpreter.\ As\ to\ the\ question\ of\ extensibility,\ it\ is\ actually\ fairly\ simple\ to\ extend\na\ switch-based\ interpreter\ without\ altering\ the\ original\ with\ a\ little\ forethought.\ All\ you\ \nneed\ to\ do\ is\ to\ use\ open-recursion\ and\ an\ explicit\ fixpoint\ operator\ (here\ we\nadd\ support\ for\ environments\ too\;\ \[dict\]\ required):\n======\n\ proc\ calc\ \{self\ expr\ env\}\ \{\n\ \ \ \ \ lassign\ \$expr\ op\ a\ b\n\ \ \ \ \ switch\ -exact\ --\ \$op\ \{\n\ \ \ \ \ \ \ \ \ +\ \ \ \ \ \ \ \{\ expr\ \{\[call\ \$self\ \$a\ \$env\]\ +\ \[call\ \$self\ \$b\ \$env\]\}\ \}\n\ \ \ \ \ \ \ \ \ -\ \ \ \ \ \ \ \{\ expr\ \{\[call\ \$self\ \$a\ \$env\]\ -\ \[call\ \$self\ \$b\ \$env\]\}\ \}\n\ \ \ \ \ \ \ \ \ *\ \ \ \ \ \ \ \{\ expr\ \{\[call\ \$self\ \$a\ \$env\]\ *\ \[call\ \$self\ \$b\ \$env\]\}\ \}\n\ \ \ \ \ \ \ \ \ /\ \ \ \ \ \ \ \{\ expr\ \{\[call\ \$self\ \$a\ \$env\]\ /\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double(\[call\ \$self\ \$b\ \$env\])\}\ \}\n\ \ \ \ \ \ \ \ \ const\ \ \ \{\ return\ \$a\ \}\n\ \ \ \ \ \ \ \ \ var\ \ \ \ \ \{\ dict\ get\ \$env\ \$a\ \}\n\ \ \ \ \ \ \ \ \ default\ \{\ error\ \"unknown\ op\ \\\"\$op\\\"\"\ \}\n\ \ \ \ \ \}\n\ \}\n\ #\ fixpoint\ operator\ (similar\ to\ Y\ combinator):\n\ proc\ call\ \{cmd\ args\}\ \{\ uplevel\ #0\ \$cmd\ \[linsert\ \$args\ 0\ \$cmd\]\ \}\n======\nWe\ can\ then\ call\ our\ command\ using\ the\ fixpoint\ operator\ (which\ is\ quite\ similar\ in\ some\ ways\ to\n\[TOOT\]\ dispatch):\n======\n\ %\ set\ datum\ \{/\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\n\ /\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\n\ %\ call\ calc\ \$datum\ \{x\ 1\}\n\ 0.25\n======\nExtending\ the\ language\ to\ support\ an\ ''exp''\ operation\ is\ now\ a\ simple\ task,\ much\ like\nextending\ an\ OO\ program:\n======\n\ proc\ calcexp\ \{self\ expr\ env\}\ \{\n\ \ \ \ \ lassign\ \$expr\ op\ arg\n\ \ \ \ \ switch\ -exact\ --\ \$op\ \{\n\ \ \ \ \ \ \ \ \ exp\ \ \ \ \ \{\ expr\ \{exp(\[call\ \$self\ \$arg\ \$env\])\}\ \}\n\ \ \ \ \ \ \ \ \ default\ \{\ calc\ \$self\ \$expr\ \$env\ \}\n\ \ \ \ \ \}\n\ \}\n======\nAnd\ to\ test:\n======\n\ %\ set\ datum3\ \{exp\ \{/\ \{var\ x\}\ \{var\ y\}\}\}\n\ exp\ \{/\ \{var\ x\}\ \{var\ y\}\}\n\ %\ call\ calcexp\ \$datum3\ \{x\ 2\ y\ 1\}\n\ 7.38905609893065\n======\nNote\ that\ our\ original\ language\ is\ still\ available,\ so\ only\ those\ callers\ who\ want\ the\ extended\nlanguage\ have\ to\ get\ it:\n======\n\ %\ call\ calc\ \$datum3\ \{x\ 2\ y\ 1\}\n\ unknown\ op\ \"exp\"\n======\n\n\[NEM\]\ (A\ few\ minutes\ later):\ It's\ also\ quite\ simple\ to\ extend\ the\ language\ in\ different\ directions.\nFor\ example\ (and\ because\ it's\ fun!),\ here's\ how\ to\ add\ lexically-scoped\ \[lambda\]\ expressions\ to\nthe\ language\ (something\ Tcl\ itself\ doesn't\ have\ built-in):\n======\n\ proc\ calclam\ \{self\ expr\ env\}\ \{\n\ \ \ \ \ lassign\ \$expr\ op\ a\ b\n\ \ \ \ \ switch\ -exact\ --\ \$op\ \{\n\ \ \ \ \ \ \ \ \ lambda\ \ \{\ list\ closure\ \$a\ \$b\ \$env\ \}\n\ \ \ \ \ \ \ \ \ app\ \ \ \ \ \{\ calcapp\ \$self\ \[call\ \$self\ \$a\ \$env\]\ \[call\ \$self\ \$b\ \$env\]\ \}\n\ \ \ \ \ \ \ \ \ default\ \{\ calc\ \$self\ \$expr\ \$env\ \}\n\ \ \ \ \ \}\n\ \}\n\ proc\ calcapp\ \{self\ f\ x\}\ \{\n\ \ \ \ \ lassign\ \$f\ op\ arg\ body\ env\n\ \ \ \ \ switch\ -exact\ --\ \$op\ \{\n\ \ \ \ \ \ \ \ \ closure\ \{\ call\ \$self\ \$body\ \[dict\ replace\ \$env\ \$arg\ \$x\]\ \}\n\ \ \ \ \ \ \ \ \ default\ \{\ error\ \"not\ a\ closure:\ \\\"\$f\\\"\"\ \}\n\ \ \ \ \ \}\n\ \}\n======\nAnd\ the\ test:\n======\n\ %\ set\ f\ \{lambda\ x\ \{lambda\ y\ \{*\ \{var\ x\}\ \{var\ y\}\}\}\}\n\ lambda\ x\ \{lambda\ y\ \{*\ \{var\ x\}\ \{var\ y\}\}\}\n\ %\ set\ exp\ \[list\ app\ \[list\ app\ \$f\ \{const\ 3\}\]\ \{const\ 4\}\]\n\ app\ \{app\ \{lambda\ x\ \{lambda\ y\ \{*\ \{var\ x\}\ \{var\ y\}\}\}\}\ \{const\ 3\}\}\ \{const\ 4\}\n\ %\ call\ calclam\ \$exp\ \{\}\ \n\ 12\n======\n----\n\[NEM\]\ ''(cont.)''\ As\ you\ mention\ at\ the\ start,\ an\ \[OO\]\ approach\ makes\ it\ easy\ to\ add\ new\ types\ (just\ add\ a\ new\nsub-class\ and\ implement\ the\ operations),\ but\ trickier\ to\ add\ new\ operations,\ whereas\ a\ pattern\nmatching\ approach\ makes\ it\ easier\ to\ add\ new\ operations\ but\ harder\ to\ add\ new\ data\ types\ (as\nyou\ need\ to\ update\ all\ the\ operations).\ This\ is\ apparently\ known\ as\ the\ ''expression\ problem''\nin\ programming\ language\ design,\ and\ there\ are\ a\ number\ of\ ways\ in\ which\ it\ is\ tackled.\ The\nusual\ OO\ way\ is\ the\ \[Visitor\ pattern\],\ which\ essentially\ implements\ pattern\ matching\ over\nOO\ dispatch.\ In\ this\ case\ you'd\ have\ something\ like\ the\ following\ (psuedo-code):\n======\n\ class\ Expr\ \{\n\ \ \ \ \ abstract\ method\ visit\ \{visitor\}\n\ \}\n\ class\ Num\ val\ \{\n\ \ \ \ \ inherit\ Expr\n\ \ \ \ \ method\ visit\ \{visitor\}\ \{\ \$visitor\ visitNum\ \$val\ \}\n\ \}\n\ class\ AddOp\ a\ b\ \{\n\ \ \ \ \ inherit\ Expr\n\ \ \ \ \ method\ visit\ \{visitor\}\ \{\ \$visitor\ visitAddOp\ \$a\ \$b\ \}\n\ \}\n\ ...\n\ class\ ExprVisitor\ \{\n\ \ \ \ \ abstract\ method\ visitNum\ \{val\}\n\ \ \ \ \ abstract\ method\ visitAddOp\ \{a\ b\}\n\ \ \ \ \ ...\n\ \}\n\ class\ ExprInterp\ \{\n\ \ \ \ \ inherit\ ExprVisitor\n\ \ \ \ \ method\ visitNum\ \{val\}\ \{\ return\ \$val\ \}\n\ \ \ \ \ method\ visitAddOp\ \{a\ b\}\ \{\ expr\ \{\[\$a\ visit\ \$self\]\ +\ \[\$b\ visit\ \$self\]\}\ \}\n\ \ \ \ \ ...\n\ \}\n\ \[AddOp\ \[AddOp\ \[Num\ 2\]\ \[Num\ 5\]\]\ \[Num\ 4\]\]\ visit\ \[ExprInterp\]\ \;#\ =>\ 11\n======\nPattern\ matching\ can\ also\ be\ made\ more\ flexible\ by\ including\ default\ cases.\n\n----\n\n\[LV\]\ One\ of\ the\ examples\ I've\ read\ about,\ in\ terms\ of\ this\ topic,\ has\ to\ do\nwith\ saving\ the\ state\ of\ a\ Tcl\ program.\ The\ idea\ is\ that\ one\ would\ write\n\[proc\]s\ which\ would\ go\ through\ and\ save\ off\ the\ values\ of\ any\ variable,\nproc,\ namespace,\ etc.\ At\ first,\ I\ thought\ ''well,\ only\ the\ values\ which\nare\ dynamically\ set\ are\ necessary\ -\ the\ procs\ defined\ in\ the\ program's\nfile\ itself\ need\ not\ be\ saved,\ nor\ variables\ which\ are\ set\ within\ that\ file.''\nHowever,\ given\ that\ someone\ might\ come\ along\ and\ modify\ the\ program,\ or\nfor\ that\ matter,\ given\ that\ you\ would\ have\ to\ write\ specialized\ code\nto\ avoid\ getting\ those\ values,\ it\ is\ much\ easier\ just\ to\ save\ everything.\nIf\ done\ properly,\ the\ \"save\ file\"\ should\ be\ able\ to\ be\ invoked\ and\ the\napplication\ would\ be\ back\ the\ way\ things\ were\ (with\ some\ possible\nexceptions,\ depending\ on\ the\ code,\ extensions,\ etc.)\ when\ last\ started.\n\n----\n**See\ also**\n\nExamples\ found\ \"in\ the\ wild\"\ of\ data\ structures\ which\ support\ the\ data-is-code\ paradigm:\n\ \ \ \[parsetcl\]:\ \ \ Represents\ the\ syntactic\ structure\ of\ Tcl\ code\ as\ a\ list-tree.\ A\ wiki\ user\ contributed\ a\ set\ of\ procs\ that\ made\ the\ list-tree\ convert\ itself\ back\ to\ Tcl\ code\ when\ evaluated!\n\ \ \ \[grammar_fa\]:\ \ \ Has\ a\ list-tree\ representation\ for\ regular\ expressions.\ Node\ types\ are\ '''S''',\ '''.''',\ '''|''',\ '''&''',\ '''*''',\ '''?''',\ '''+''',\ and\ '''!'''.\n\ \ \ \[A\ little\ XML\ parser\]:\ \ \ Has\ tree-list\ representation\ (inherited\ from\ \[tdom\])\ for\ XML\ data.\ Node\ types\ are\ the\ tags\ that\ may\ occur,\ and\ #text\ for\ text\ content.\n\ \ \ \[Geometry\]:\ \ \ Represents\ geometric\ objects\ as\ list-trees,\ with\ POINT\ and\ VECTOR\ as\ leaf\ node\ types.\n\nGoing\ one\ step\ further:\ \[code\ is\ data\ is\ code\]\n----\n''\[escargo\]\ 4\ Nov\ 2008''\ -\ And\ here\ I\ thought\ the\ word\ \"data\"\ is\ plural.\ \n\n\[NEM\]:\ Singular\ or\ plural.\ \"Data\ are\ codes\"\ sounds\ weird.\n\n<<categories>>\ Concept\ |\ Control\ Structure\ |\ Data\ Structure\ |\ Design\ |\ Mathematics\ |\ Tutorial regexp2} CALL {my render {data is code} (Page\ begun\ by\ \[Lars\ H\],\ 11\ March\ 2007\;\ feel\ free\ to\ expand.)\n\n'''Data\ is\ code'''\ is\ a\ powerful\ programming\ technique\ for\ working\ \nwith\ complicated\ data,\ especially\ tree-like\ data.\ The\ idea\ is\ that\ \nthe\ data\ structure\ itself\ can\ also\ be\ regarded\ as\ a\ command,\ so\ \nthat\ traversing\ a\ data\ structure\ can\ simply\ be\ to\ \[eval\]uate\ it!\ \nBy\ providing\ different\ definitions\ (of\ the\ basic\ node\ types)\ in\ \ndifferent\ \[namespace\]s,\ it\ is\ possible\ to\ implement\ a\ variety\ of\ \ndifferent\ operations\ as\ evaluations\ of\ the\ same\ data\ structure.\n\nThe\ idea\ supports\ \[polymorphism\]\ to\ about\ the\ same\ degree\ as\ \nObject-oriented\ Programming,\ but\ does\ so\ in\ a\ quite\ different\ way.\ \nWhile\ it\ in\ \[OOP\]\ is\ the\ data\ (objects)\ that\ have\ to\ know\ all\ the\ \noperations\ (methods)\ that\ may\ act\ upon\ it,\ data-is-code\ requires\ that\ \nthe\ operations\ (in\ this\ setting:\ namespaces)\ know\ all\ the\ types\ of\ \ndata\ that\ they\ may\ encounter.\ Both\ support\ extensions\ to\ about\ \nthe\ same\ degree:\n\ \ \ *\ In\ OOP,\ a\ new\ type\ can\ be\ implemented\ as\ a\ new\ class,\ whereas\ a\ new\ operation\ can\ be\ implemented\ as\ a\ new\ method\ on\ the\ ancestor\ class.\n\ \ \ *\ With\ data-is-code,\ a\ new\ type\ is\ implemented\ by\ defining\ commands\ for\ it\ in\ all\ operation\ namespaces,\ whereas\ a\ new\ operation\ is\ implemented\ as\ a\ new\ namespace.\nWhere\ OOP\ can\ use\ inheritance\ to\ share\ some\ operation\ definitions\ \n(make\ them\ the\ same\ as\ for\ some\ other\ type),\ data-is-code\ can\ do\ the\ \nsame\ by\ creating\ aliases.\ The\ main\ difference\ is\ that\ objects,\ being\ \ncommands\ even\ in\ cases\ where\ they're\ primarily\ used\ as\ containers\ for\ \ndata,\ need\ to\ be\ explicitly\ destroyed\ and\ therefore\ objects\ add\ the\ \nburden\ of\ lifetime\ management.\ Pure\ data\ that\ is\ sometimes\ treated\ as\ \ncode\ does\ not\ have\ that\ problem.\n\n\[TOOT\]\ is\ a\ bit\ of\ a\ \[data\ is\ code\]/\[OO\]\ hybrid.\ Its\ basic\ mechanism\ is\ to\ treat\ data\ as\ code\ (and\ thus\ doesn't\ have\ the\ lifetime\ management\ problem),\ but\ the\ only\ operation\ implemented\ is\ OO-style\ method\ dispatch.\n----\n**An\ example:\ Algebraic\ expressions**\n\nAn\ example\ which\ illustrates\ many\ of\ these\ points\ can\ be\ provided\ by\ \na\ data\ structure\ for\ simple\ algebraic\ expressions.\ Suppose\ an\ \n''expression''\ is\ a\ list\ on\ one\ of\ the\ forms\n\ \ \ \ :\ \ \ '''+'''\ ''expression''\ ''expression''\n\ \ \ \ :\ \ \ '''-'''\ ''expression''\ ''expression''\n\ \ \ \ :\ \ \ '''*'''\ ''expression''\ ''expression''\n\ \ \ \ :\ \ \ '''/'''\ ''expression''\ ''expression''\n\ \ \ \ :\ \ \ '''var'''\ ''name''\n\ \ \ \ :\ \ \ '''const'''\ ''value''\nWith\ the\ obvious\ interpretation\ of\ +,\ -,\ etc.,\ we\ find\ that\ the\ \nexpression\ (2x-1)/(x+3)\ is\ represented\ by\ the\ data\ structure\n======\n\ \ /\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\n======\n\nSo\ far,\ this\ is\ just\ a\ data\ structure\;\ there\ are\ no\ operations\ which\ \nact\ on\ it.\ (The\ +,\ -,\ and\ friends\ are\ node\ types\ in\ the\ general\ \nterminology\ above.)\ A\ very\ natural\ operation\ would\ however\ be\ to\ \nevaluate\ the\ expression,\ which\ can\ be\ implemented\ as\ follows:\n\n======\n\ \ namespace\ eval\ algexpr::eval\ \{\n\ \ \ \ \ proc\ +\ \{term1\ term2\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$term1\]\ +\ \[eval\ \$term2\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$term1\]\ -\ \[eval\ \$term2\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$factor1\]\ *\ \[eval\ \$factor2\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{numer\ denom\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$numer\]\ /\ double(\[eval\ \$denom\])\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ const\ \{val\}\ \{return\ \$val\}\n\ \ \ \ \ proc\ var\ \{name\}\ \{\n\ \ \ \ \ \ \ \ upvar\ #0\ \$name\ val\n\ \ \ \ \ \ \ \ return\ \$val\n\ \ \ \ \ \}\n\ \ \}\n======\nThe\ command\ to\ actually\ evaluate\ an\ expression\ \$datum\ is\ then\n======\n\ \ namespace\ inscope\ algexpr::eval\ \$datum\n======\n(or\ \[\[namespace\ eval\ algexpr::eval\ \$datum\]\],\ but\ the\ syntax\ of\ \n\[namespace\ inscope\]\ is\ often\ more\ appropriate).\n\n======\n\ \ %\ set\ datum\ \{/\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\n\ \ %\ set\ x\ 1\n\ \ %\ namespace\ inscope\ algexpr::eval\ \$datum\n\ \ 0.25\n\ \ %\ set\ x\ 2\n\ \ %\ namespace\ inscope\ algexpr::eval\ \$datum\n\ \ 0.6\n\ \ %\ set\ x\ 3\n\ \ %\ namespace\ inscope\ algexpr::eval\ \$datum\n\ \ 0.833333333333\n======\n\nWorks\ fine,\ but\ it\ is\ probably\ not\ all\ that\ practical\ to\ fetch\ the\ \nvariable\ values\ from\ global\ variables.\ A\ more\ natural\ construction\ is\ \nto\ provide\ them\ in\ the\ evaluation\ call,\ but\ that\ requires\ a\ different\ \nset\ of\ definitions,\ and\ is\ thus\ a\ different\ operation.\n======\n\ \ namespace\ eval\ algexpr::eval2\ \{\n\ \ \ \ \ proc\ +\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$term1\ \$args\]\ +\ \[eval\ \$term2\ \$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$term1\ \$args\]\ -\ \[eval\ \$term2\ \$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$factor1\ \$args\]\ *\ \[eval\ \$factor2\ \$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{numer\ denom\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[eval\ \$numer\ \$args\]\ /\ double(\[eval\ \$denom\ \$args\])\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ const\ \{val\ args\}\ \{return\ \$val\}\n\ \ \ \ \ proc\ var\ \{name\ args\}\ \{\n\ \ \ \ \ \ \ \ foreach\ \{var\ val\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$name\ eq\ \$var\}\ then\ \{return\ \$val\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ error\ \"No\ value\ specified\ for\ '\$name'\"\n\ \ \ \ \ \}\n\ \ \}\n======Commands\ corresponding\ to\ the\ above\ are\ now\n======\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$datum\ x\ 1\n\ \ 0.25\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$datum\ x\ 2\n\ \ 0.6\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$datum\ x\ 3\n\ \ 0.833333333333\n======\nand\ it's\ not\ much\ harder\ to\ handle\ expressions\ involving\ several\ \nvariables\n======\n\ \ %\ set\ datum2\ \{/\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{var\ y\}\ \{const\ 3\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$datum2\ x\ 1\ y\ 2\n\ \ 0.2\n======\n(Using\ \[namespace\ eval\]\ instead\ would\ require\ \[list\]-quoting\ the\ \nextra\ arguments,\ which\ is\ a\ bit\ artificial.)\n\nEvaluating\ expressions\ is\ a\ rather\ simple\ operation\ however,\ so\ what\ \nabout\ something\ trickier,\ like\ differentiation?\ This\ would\ mean\ that\n======\n\ \ namespace\ inscope\ algexpr::diff\ \$datum\ \$var\n======\nreturns\ the\ derivative\ of\ \$datum\ with\ respect\ to\ \$var.\ The\ basic\ \ndifferentiation\ rules\ are\ straightforward\ to\ implement:\n======\n\ \ namespace\ eval\ algexpr::diff\ \{\n\ \ \ \ \ proc\ +\ \{term1\ term2\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ +\ \[eval\ \$term1\ \[list\ \$var\]\]\ \[eval\ \$term2\ \[list\ \$var\]\]\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ -\ \[eval\ \$term1\ \[list\ \$var\]\]\ \[eval\ \$term2\ \[list\ \$var\]\]\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ +\ \[\n\ \ \ \ \ \ \ \ \ \ \ list\ *\ \[eval\ \$factor1\ \[list\ \$var\]\]\ \$factor2\n\ \ \ \ \ \ \ \ \]\ \[\n\ \ \ \ \ \ \ \ \ \ \ list\ *\ \$factor1\ \[eval\ \$factor2\ \[list\ \$var\]\]\n\ \ \ \ \ \ \ \ \]\n\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{factor1\ factor2\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ /\ \[\n\ \ \ \ \ \ \ \ \ \ \ list\ -\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ *\ \[eval\ \$factor1\ \[list\ \$var\]\]\ \$factor2\n\ \ \ \ \ \ \ \ \ \ \ \]\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ *\ \$factor1\ \[eval\ \$factor2\ \[list\ \$var\]\]\n\ \ \ \ \ \ \ \ \ \ \ \]\n\ \ \ \ \ \ \ \ \]\ \[\n\ \ \ \ \ \ \ \ \ \ \ list\ *\ \$factor2\ \$factor2\n\ \ \ \ \ \ \ \ \]\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ const\ \{val\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ const\ 0\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ var\ \{name\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ const\ \[expr\ \{\$name\ eq\ \$var\}\]\n\ \ \ \ \ \}\n\ \ \}\n======\nSo\ from\ this\ one\ may\ get\n======\n\ \ %\ set\ ddx_datum\ \[namespace\ inscope\ algexpr::diff\ \$datum\ x\]\n\ \ /\ \{-\ \{*\ \{-\ \{+\ \{*\ \{const\ 0\}\ \{var\ x\}\}\ \{*\ \{const\ 2\}\ \{const\ 1\}\}\}\ \{const\ 0\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\ \{*\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{const\ 1\}\ \{const\ 0\}\}\}\}\ \{*\ \{+\ \{var\ x\}\ \{const\ 3\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$ddx_datum\ x\ 2\n\ \ 0.28\n======\nwhich\ fits\ well\ with\ the\ values\ computed\ before.\n\nWhat\ does\ the\ \$ddx_datum\ expression\ look\ like\ in\ more\ traditional\ \nnotation,\ though?\ Conversion\ to\ \[expr\]\ syntax\ is\ of\ course\ another\ \noperation,\ so\ now\ that\ we're\ warmed\ up,\ it\ is\ probably\ easier\ to\ \nimplement\ it\ than\ to\ decipher\ the\ \$ddx_datum\ by\ hand.\ The\ only\ issue\ \none\ needs\ to\ solve\ is\ how\ to\ know\ when\ to\ insert\ parentheses,\ but\ \nthat's\ easily\ handled\ by\ specifying\ the\ operation\ to\ be\ to\n\ \ \ *\ convert\ an\ algexpr\ to\ \[expr\]\ form\ such\ that\ it\ can\ safely\ be\ made\ an\ operand\ of\ an\ expr-operation\ with\ priority\ ''priority'',\ where\ 0\ means\ no\ operation,\ 1\ means\ +,\ 2\ means\ *,\ and\ 3\ is\ as\ denominator.\nThe\ following\ will\ then\ do\ the\ trick\n======\n\ \ namespace\ eval\ algexpr::toexpr\ \{\n\ \ \ \ \ proc\ +\ \{term1\ term2\ priority\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \"\[eval\ \$term1\ \[list\ 1\]\]+\[eval\ \$term2\ \[list\ 1\]\]\"\n\ \ \ \ \ \ \ \ if\ \{\$priority>1\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\$res)\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \$res\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\ priority\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \"\[eval\ \$term1\ \[list\ 1\]\]-\[eval\ \$term2\ \[list\ 2\]\]\"\n\ \ \ \ \ \ \ \ if\ \{\$priority>1\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\$res)\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \$res\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\ priority\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \"\[eval\ \$factor1\ \[list\ 2\]\]*\[eval\ \$factor2\ \[list\ 2\]\]\"\n\ \ \ \ \ \ \ \ if\ \{\$priority>2\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\$res)\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \$res\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{numer\ denom\ priority\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \"\[eval\ \$numer\ \[list\ 2\]\]/\[eval\ \$denom\ \[list\ 3\]\]\"\n\ \ \ \ \ \ \ \ if\ \{\$priority>2\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\$res)\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \$res\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ var\ \{name\ priority\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ -nocase\ --\ \{^\[a-z_\]\[a-z0-9_\]*\$\}\ \$name\]\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \"\\\$\$name\"\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ \"\\\[\[list\ set\ \$name\]\\\]\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ const\ \{val\ priority\}\ \{return\ \$val\}\n\ \ \}\n======\nThe\ right\ command\ to\ reformat\ our\ first\ \$datum\ is\ thus\n======\n\ \ %\ namespace\ inscope\ algexpr::toexpr\ \$datum\ 0\n\ \ (2*\$x-1)/(\$x+3)\n======\nWorks\ like\ a\ charm!\ Now\ what\ about\ that\ derivative?\n======\n\ \ %\ namespace\ inscope\ algexpr::toexpr\ \$ddx_datum\ 0\n\ \ ((0*\$x+2*1-0)*(\$x+3)-(2*\$x-1)*(1+0))/((\$x+3)*(\$x+3))\n======\nHmmm...\ It's\ ''correct'',\ but\ not\ very\ nice\ --\ there\ are\ a\ lot\ of\ \nconstant\ subexpressions\ that\ any\ human\ would\ have\ evaluated\ during\ \nthe\ differentiation\ operation.\ One\ way\ to\ get\ rid\ of\ these\ would\ be\ \nto\ improve\ the\ differentiation\ operation\ to\ do\ these\ simplifications\ \non\ the\ fly,\ but\ another\ is\ to\ implement\ a\ more\ generic\ operation\ for\ \n''partial\ evaluation''\ of\ expressions.\ The\ actual\ situations\ one\ has\ \nto\ deal\ with\ are\ the\ same\ in\ both\ cases,\ so\ the\ more\ generic\ \noperation\ seems\ preferable.\n\n======\n\ \ namespace\ eval\ algexpr::parteval\ \{\n\ \ \ \ \ proc\ const\ \{val\ args\}\ \{list\ const\ \$val\}\n\ \ \ \ \ proc\ var\ \{name\ args\}\ \{\n\ \ \ \ \ \ \ \ foreach\ \{var\ val\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$name\ eq\ \$var\}\ then\ \{return\ \[list\ const\ \$val\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ var\ \$name\]\n\ \ \ \ \ \}\n\ \ \ \ \ #\ These\ two\ were\ the\ central\ ones,\ but\ most\ of\ the\ actual\ \n\ \ \ \ \ #\ work\ remains,\ since\ there\ are\ many\ small\ cases\ where\n\ \ \ \ \ #\ partial\ evaluation\ is\ possible.\n\ \ \ \ \ proc\ +\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ res1\ \[eval\ \$term1\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t1\ v1\}\ \$res1\ break\n\ \ \ \ \ \ \ \ set\ res2\ \[eval\ \$term2\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t2\ v2\}\ \$res2\ break\n\ \ \ \ \ \ \ \ if\ \{\$t1\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$t2\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ \[expr\ \{\$v1\ +\ \$v2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$v1==0\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ res2\n\ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ +\ \$res2\ \$res1\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$t2\ eq\ \"const\"\ &&\ \$v2==0\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ res1\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ +\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ res1\ \[eval\ \$term1\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t1\ v1\}\ \$res1\ break\n\ \ \ \ \ \ \ \ set\ res2\ \[eval\ \$term2\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t2\ v2\}\ \$res2\ break\n\ \ \ \ \ \ \ \ if\ \{\$t1\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$t2\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ \[expr\ \{\$v1\ -\ \$v2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ -\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$t2\ eq\ \"const\"\ &&\ \$v2==0\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ res1\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ -\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ res1\ \[eval\ \$factor1\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t1\ v1\}\ \$res1\ break\n\ \ \ \ \ \ \ \ set\ res2\ \[eval\ \$factor2\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t2\ v2\}\ \$res2\ break\n\ \ \ \ \ \ \ \ if\ \{\$t1\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$t2\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ \[expr\ \{\$v1\ *\ \$v2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$v1==0\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ 0\n\ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$v1==1\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ res2\n\ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ *\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$t2\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$v2==0\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ 0\n\ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$v2==1\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ res1\n\ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ *\ \$res2\ \$res1\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ *\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{numer\ denom\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ res1\ \[eval\ \$numer\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t1\ v1\}\ \$res1\ break\n\ \ \ \ \ \ \ \ set\ res2\ \[eval\ \$denom\ \$args\]\n\ \ \ \ \ \ \ \ foreach\ \{t2\ v2\}\ \$res2\ break\n\ \ \ \ \ \ \ \ if\ \{\$t2\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$t1\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ const\ \[expr\ \{\$v1\ /\ double(\$v2)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$v2==1\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ res1\n\ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ /\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ /\ \$res1\ \$res2\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \}\n======\n\nSome\ examples:\n======\n\ \ %\ namespace\ inscope\ algexpr::parteval\ \$datum\ x\ 2\n\ \ const\ 0.6\n\ \ %\ namespace\ inscope\ algexpr::parteval\ \$datum2\ x\ 2\n\ \ /\ \{const\ 3\}\ \{+\ \{var\ y\}\ \{const\ 3\}\}\n======\nSo,\ what\ about\ that\ ugly\ derivative?\n======\n\ \ %\ set\ ddx_datum_simplified\ \[namespace\ inscope\ algexpr::parteval\ \$ddx_datum\]\n\ \ /\ \{-\ \{*\ \{const\ 2\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\}\ \{*\ \{+\ \{var\ x\}\ \{const\ 3\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::toexpr\ \$ddx_datum_simplified\ 0\n\ \ (2*(\$x+3)-(2*\$x-1))/((\$x+3)*(\$x+3))\n======\nBetter,\ but\ still\ redundant.\ (Simplifying\ algebraic\ expressions\ to\ \nabout\ the\ degree\ expected\ from\ a\ math\ student\ is\ really\ rather\ \ncomplicated,\ once\ you\ have\ to\ instruct\ a\ computer\ to\ do\ it,\ and\ this\ \nrepresentation\ with\ binary\ +,\ -,\ *,\ and\ /\ is\ not\ very\ practical\ for\ \nthe\ task.\ Better\ solutions\ are\ beyond\ the\ simple\ example,\ however.)\n\nLet\ us\ instead\ consider\ how\ to\ extend\ the\ algexpr\ data\ structure\ with\ \na\ new\ node\ type,\ say\ '''exp'''\ for\ the\ (natural\ base)\ exponential\ \nfunction.\ This\ requires\ defining\ exp\ procedures\ in\ all\ the\ namespaces\ \nwhere\ this\ node\ type\ may\ be\ expected:\n======\n\ \ namespace\ eval\ algexpr::eval\ \{\n\ \ \ \ \ proc\ exp\ \{arg\}\ \{expr\ \{exp(\[eval\ \$arg\])\}\}\n\ \ \}\n\ \ namespace\ eval\ algexpr::eval2\ \{\n\ \ \ \ \ proc\ exp\ \{arg\ args\}\ \{expr\ \{exp(\[eval\ \$arg\ \$args\])\}\}\n\ \ \}\n\ \ namespace\ eval\ algexpr::diff\ \{\n\ \ \ \ \ proc\ exp\ \{arg\ var\}\ \{\n\ \ \ \ \ \ \ \ list\ *\ \[list\ exp\ \$arg\]\ \[eval\ \$arg\ \[list\ \$var\]\]\n\ \ \ \ \ \}\n\ \ \}\n\ \ namespace\ eval\ algexpr::toexpr\ \{\n\ \ \ \ \ proc\ exp\ \{arg\ priority\}\ \{return\ \"exp(\[eval\ \$arg\ \[list\ 0\]\])\"\}\n\ \ \}\n\ \ namespace\ eval\ algexpr::parteval\ \{\n\ \ \ \ \ proc\ exp\ \{arg\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ ares\ \[eval\ \$arg\ \$args\]\n\ \ \ \ \ \ \ \ if\ \{\[lindex\ \$ares\ 0\]\ eq\ \"const\"\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ const\ \[expr\ \{exp(\[lindex\ \$ares\ 1\])\}\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ list\ exp\ \$ares\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\n\ \ \}\n======\nThat's\ all\ there\ is\ to\ it:\n======\n\ \ %\ set\ datum3\ \{exp\ \{/\ \{var\ x\}\ \{var\ y\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::eval2\ \$datum3\ x\ 2\ y\ 1\n\ \ 7.38905609893\n\ \ %\ set\ ddy_datum3\ \[namespace\ inscope\ algexpr::diff\ \$datum3\ y\]\n\ \ *\ \{exp\ \{/\ \{var\ x\}\ \{var\ y\}\}\}\ \{/\ \{-\ \{*\ \{const\ 0\}\ \{var\ y\}\}\ \{*\ \{var\ x\}\ \{const\ 1\}\}\}\ \{*\ \{var\ y\}\ \{var\ y\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::toexpr\ \$ddy_datum3\ 0\n\ \ exp(\$x/\$y)*(0*\$y-\$x*1)/(\$y*\$y)\n\ \ %\ set\ ddy_datum3\ \[namespace\ inscope\ algexpr::parteval\ \$ddy_datum3\]\n\ \ *\ \{exp\ \{/\ \{var\ x\}\ \{var\ y\}\}\}\ \{/\ \{-\ \{const\ 0\}\ \{var\ x\}\}\ \{*\ \{var\ y\}\ \{var\ y\}\}\}\n\ \ %\ namespace\ inscope\ algexpr::toexpr\ \$ddy_datum3\ 0\n\ \ exp(\$x/\$y)*(0-\$x)/(\$y*\$y)\n======\n\n----\n**Sharing\ commands**\n\nThe\ examples\ above\ never\ gave\ an\ opportunity\ to\ use\ the\ same\ command\ \nfor\ more\ than\ one\ thing,\ but\ using\ \[interp\ alias\]\ or\ \[namespace\ import\]\ \nto\ make\ one\ command\ appear\ in\ several\ places\ is\ a\ standard\ Tcl\ \nprogramming\ technique\ that\ is\ explained\ elsewhere.\ There\ are\ however\ \nsome\ special\ issues\ one\ should\ take\ note\ of:\n\n\ \ \ Avoid\ colons\ in\ node\ types:\ \ \ Colons\ interact\ strangely\ with\ the\ namespace\ separator\ ::,\ so\ you\ may\ be\ unable\ to\ make\ use\ of,\ or\ even\ speak\ about,\ the\ command\ you\ want.\n\n\ \ \ Be\ aware\ of\ the\ namespace\ context:\ \ \ If\ you\ import\ or\ alias\ a\ proc\ into\ a\ namespace,\ then\ the\ namespace\ context\ of\ this\ proc\ does\ ''not''\ follow.\ For\ set-ups\ such\ as\ the\ above,\ where\ the\ namespace\ context\ is\ an\ essential\ foundation\ for\ the\ interpretation,\ this\ can\ be\ disastrous.\n\nThere\ is\ a\ rather\ simple\ solution\ to\ the\ namespace\ problem,\ however:\ \nuse\ \[uplevel\]\ instead\ of\ \[eval\]!\ This\ works\ because\ it\ causes\ a\ child\ \nnode\ to\ be\ interpreted\ as\ a\ command\ in\ the\ same\ context\ as\ the\ parent\ \nnode\ was,\ so\ if\ for\ example\ the\ child\ and\ parent\ nodes\ are\ of\ the\ \nsame\ type\ then\ they\ will\ both\ be\ handled\ by\ the\ same\ command.\ \n\nIf\ this\ still\ seem\ mysterious\ to\ you,\ then\ remember\ that\ \n\[namespace\ eval\]\ and\ kin\ (e.g.\ \[namespace\ inscope\])\ adds\ a\ level\ \nvisible\ to\ \[uplevel\].\ The\ following\ provides\ an\ example:\n======\n\ \ namespace\ eval\ ::foo\ \{\}\n\ \ proc\ ::a\ \{\}\ \{\n\ \ \ \ \ puts\ \"-\ I'm\ ::a,\ called\ as\ \[info\ level\ 0\].\"\n\ \ \ \ \ return\ ::a\n\ \ \}\n\ \ proc\ ::foo::a\ \{\}\ \{\n\ \ \ \ \ puts\ \"-\ I'm\ ::foo::a,\ called\ as\ \[info\ level\ 0\].\"\n\ \ \ \ \ return\ ::foo::a\n\ \ \}\n\ \ proc\ ::b\ \{\}\ \{\n\ \ \ \ \ puts\ -nonewline\ \"-\ I'm\ ::b,\ called\ as\ \[info\ level\ 0\]\;\ \"\n\ \ \ \ \ puts\ \"my\ namespace\ is\ \[namespace\ current\].\"\n\ \ \ \ \ puts\ \"::b\ says:\ I've\ just\ called\ \[uplevel\ 1\ a\].\"\n\ \ \}\n\ \ interp\ alias\ \{\}\ ::foo::b\ \{\}\ ::b\n======\nThe\ call\ \[\[b\]\]\ prints\n\ \ -\ I'm\ ::b,\ called\ as\ b\;\ my\ namespace\ is\ ::.\n\ \ -\ I'm\ ::a,\ called\ as\ a.\n\ \ ::b\ says:\ I've\ just\ called\ ::a.\nand\ the\ call\ \[\[namespace\ inscope\ foo\ b\]\]\ prints\n\ \ -\ I'm\ ::b,\ called\ as\ ::b\;\ my\ namespace\ is\ ::.\n\ \ -\ I'm\ ::foo::a,\ called\ as\ a.\n\ \ ::b\ says:\ I've\ just\ called\ ::foo::a.\nbecause\ '''b'''\ calls\ the\ '''a'''\ visible\ in\ the\ namespace\ from\ which\ \n'''b'''\ itself\ was\ called,\ even\ if\ that\ isn't\ where\ '''b'''\ resides.\n\nAn\ alternative\ approach\ to\ the\ namespace\ problem,\ which\ can\ be\ useful\ \nfor\ generic\ utility\ commands\ (that\ via\ aliases\ with\ some\ extra\ \narguments\ can\ implement\ a\ whole\ score\ of\ commands),\ is\ to\ supply\ the\ \nintended\ namespace\ as\ an\ extra\ argument.\ Then\ if\ one\ defines\n======\n\ \ proc\ exprbinop\ \{ns\ op\ left\ right\ args\}\ \{\n\ \ \ \ \ set\ leftval\ \[namespace\ eval\ \$ns\ \$left\ \$args\]\n\ \ \ \ \ set\ rightval\ \[namespace\ eval\ \$ns\ \$right\ \$args\]\n\ \ \ \ \ expr\ \\\$leftval\ \$op\ \\\$rightval\n\ \ \}\n======\nthe\ algexpr::eval\ and\ algexpr::eval2\ implementations\ of\ +,\ -,\ and\ *\ \ncan\ all\ be\ given\ as\ aliases\ to\ this\ exprbinop:\n======\n\ \ interp\ alias\ \{\}\ algexpr::eval::+\ \{\}\ exprbinop\ algexpr::eval\ +\n\ \ interp\ alias\ \{\}\ algexpr::eval::-\ \{\}\ exprbinop\ algexpr::eval\ -\n\ \ interp\ alias\ \{\}\ algexpr::eval::*\ \{\}\ exprbinop\ algexpr::eval\ *\n\ \ interp\ alias\ \{\}\ algexpr::eval2::+\ \{\}\ exprbinop\ algexpr::eval2\ +\n\ \ interp\ alias\ \{\}\ algexpr::eval2::-\ \{\}\ exprbinop\ algexpr::eval2\ -\n\ \ interp\ alias\ \{\}\ algexpr::eval2::*\ \{\}\ exprbinop\ algexpr::eval2\ *\n======\nUsing\ \[uplevel\]\ is\ however\ an\ easier\ solution,\ as\ long\ as\ one\ can\ \npredict\ what\ level\ to\ uplevel\ to.\n\n----\n**Handling\ unknown\ node\ types**\n\nIn\ some\ cases,\ the\ set\ of\ possible\ node\ types\ is\ not\ known\ from\ start,\ but\ all\ except\ a\ known\ set\ of\ nodes\ are\ to\ be\ given\ default\ processing\ (which\ is\ typically\ to\ do\ nothing\ here,\ but\ recursively\ process\ all\ the\ children).\ This\ is\ a\ problem\ for\ the\ \[namespace\ inscope\]\ technique,\ since\ there\ is\ no\ way\ to\ stop\ Tcl\ from\ looking\ outside\ the\ namespace\ \ for\ command\ definitions:\ \[namespace\ path\]\ can\ be\ used\ to\ make\ Tcl\ look\ in\ additional\ namespaces,\ and\ \[namespace\ unknown\]\ can\ be\ used\ to\ override\ the\ generic\ \[unknown\],\ but\ there\ is\ no\ way\ to\ prevent\ commands\ in\ the\ ::\ namespace\ from\ being\ found\ as\ legitimate\ implementations\ of\ a\ the\ operation\ on\ a\ node.\ If\ \[list\],\ \[set\],\ \[expr\],\ or\ the\ like\ can\ occur\ as\ node\ types\ then\ this\ means\ you're\ in\ trouble.\n\nOne\ way\ to\ get\ around\ this\ could\ be\ to\ make\ sure\ that\ the\ ::\ namespace\ is\ empty,\ by\ using\ an\ \[empty\ interpreter\]\ like\ so:\n======\n\ \ interp\ create\ -safe\ dispatch\n\ \ dispatch\ hide\ namespace\n\ \ dispatch\ invokehidden\ namespace\ delete\ ::\n======\nafter\ which\ you\ can\ create\ your\ node\ types\ as\ aliases\ from\ dispatch\ to\ your\ main\ interpreter,\ and\ process\ a\ node\ by\ doing\n\ \ \ \ :\ \ \ '''dispatch\ invokehidden\ namespace\ inscope'''\ ''namespace''\ ''node''\ ?''arg''\ ...?\nbut\ this\ is\ rather\ complicated.\n\nAs\ of\ Tcl\ 8.5,\ a\ better\ approach\ is\ to\ use\ an\ ensemble\ to\ do\ the\ dispatch,\ since\ this\ does\ not\ look\ outside\ its\ given\ namespace.\ The\ set-up\ closest\ to\ that\ of\ \[namespace\ inscope\]\ is\ to\ do\n======\n\ \ namespace\ eval\ \$operation\ \{\n\ \ \ \ \ \ namespace\ export\ *\n\ \ \ \ \ \ namespace\ ensemble\ create\ -prefix\ 0\n\ \ \}\n======\nafter\ which\ the\ counterpart\ of\n======\n\ \ namespace\ inscope\ \$operation\ \$node\ \$arg\n======\nis\n======\n\ \ \$operation\ \{*\}\$node\ \$arg\n======\ne.g.\n======\n\ \ algexpr::eval2\ \{*\}\$datum\ x\ 1\n======\ninstead\ of\n======\n\ \ namespace\ inscope\ algexpr::eval2\ \$datum\ x\ 1\n======\nThis\ will\ throw\ an\ error\ when\ the\ node\ type\ is\ unknown\;\ to\ do\ something\ else\ one\ must\ supply\ an\ '''-unknown'''\ handler\ for\ the\ ensemble.\n\nA\ problem\ with\ this\ set-up\ is\ however\ that\ it\ is\ less\ obvious\ how\ to\ make\ recursive\ calls\ for\ children\;\ an\ \[eval\]\ or\ \[uplevel\]\ on\ a\ child\ will\ not\ reinvoke\ the\ ensemble\ (thus\ losing\ the\ protection\ against\ unknown\ node\ types).\ Hardcoding\ the\ fully\ qualified\ name\ of\ the\ ensemble\ where\ one\ needs\ to\ make\ a\ recursive\ call\ is\ one\ option,\ but\ that\ gets\ inconvenient\ for\ nested\ namespaces.\ When\ the\ ensemble\ (as\ is\ the\ default)\ has\ the\ same\ name\ as\ its\ namespace,\ its\ name\ can\ be\ obtained\ as\ \[\[namespace\ current\]\],\ e.g.\n======\n\ \ \ \ \ proc\ +\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[\[namespace\ current\]\ \{*\}\$term1\ \{*\}\$args\]\ +\ \[\[namespace\ current\]\ \{*\}\$term2\ \{*\}\$args\]\}\n\ \ \ \ \ \}\n======\nbut\ this\ is\ prolix\ too,\ and\ leads\ to\ \[shimmering\]\ (command\ look-up\ cannot\ be\ cached,\ as\ the\ name\ is\ regenerated\ whenever\ it\ is\ used).\ A\ better\ approach\ is\ often\ to\ place\ the\ ensemble\ command\ ''inside''\ its\ own\ namespace,\ as\ this\ makes\ it\ callable\ without\ namespace\ qualification.\ Using\ the\ empty\ string\ as\ name\ of\ the\ ensemble\ command,\ this\ can\ look\ as\ follows:\n\n======\n\ \ namespace\ eval\ algexpr::eval2\ \{\n\ \ \ \ \ proc\ +\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[\"\"\ \{*\}\$term1\ \{*\}\$args\]\ +\ \[\"\"\ \{*\}\$term2\ \{*\}\$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ -\ \{term1\ term2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[\"\"\ \{*\}\$term1\ \{*\}\$args\]\ -\ \[\"\"\ \{*\}\$term2\ \{*\}\$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ *\ \{factor1\ factor2\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[\"\"\ \{*\}\$factor1\ \{*\}\$args\]\ *\ \[\"\"\ \{*\}\$factor2\ \{*\}\$args\]\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ /\ \{numer\ denom\ args\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[\"\"\ \{*\}\$numer\ \{*\}\$args\]\ /\ double(\[\"\"\ \{*\}\$denom\ \{*\}\$args\])\}\n\ \ \ \ \ \}\n\ \ \ \ \ proc\ const\ \{val\ args\}\ \{return\ \$val\}\n\ \ \ \ \ proc\ var\ \{name\ args\}\ \{\n\ \ \ \ \ \ \ \ foreach\ \{var\ val\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ if\ \{\$name\ eq\ \$var\}\ then\ \{return\ \$val\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ error\ \"No\ value\ specified\ for\ '\$name'\"\n\ \ \ \ \ \}\n\ \ \ \ \ namespace\ export\ ?*\n\ \ \ \ \ namespace\ ensemble\ create\ -command\ \[namespace\ current\]::\ \\\n\ \ \ \ \ \ \ \ -prefix\ 0\ -unknown\ \[list\ ::default_to_type\ +\]\n\ \ \ \ \ interp\ alias\ \{\}\ \[namespace\ current\]\ \{\}\ \[namespace\ current\]::\n\ \ \}\n\ \ proc\ default_to_type\ \{type\ ensemble\ args\}\ \{list\ \$ensemble\ \$type\}\n======\n\nThe\ \[interp\ alias\]\ is\ so\ that\ the\ ensemble\ can\ still\ be\ called\ by\ external\ users\ as\ if\ it\ had\ the\ same\ name\ as\ its\ namespace.\ Using\ ?*\ as\ export\ pattern\ means\ all\ commands\ in\ the\ namespace\ ''except''\ the\ ensemble\ command\ itself\ are\ available\ as\ node\ types.\ The\ '''-unknown'''\ handler\ means\ all\ unknown\ node\ types\ are\ treated\ as\ if\ they\ were\ '''+''':\n======\n\ \ %\ algexpr::eval2\ +\ \{const\ 1\}\ \{var\ x\}\ x\ 2\n\ \ 3\n\ \ %\ algexpr::eval2\ -\ \{const\ 1\}\ \{var\ x\}\ x\ 2\n\ \ -1\n\ \ %\ algexpr::eval2\ /\ \{const\ 1\}\ \{var\ x\}\ x\ 2\n\ \ 0.5\n\ \ %\ algexpr::eval2\ &\ \{const\ 1\}\ \{var\ x\}\ x\ 2\n\ \ 3\n======\n\n----\n**Traversals\ with\ state**\n\nSometimes,\ it\ is\ important\ to\ maintain\ a\ state\ when\ traversing\ a\ data\ \nstructure,\ and\ update\ that\ state\ for\ each\ node\ processed.\ That\ each\ \nnode\ is\ processed\ in\ a\ separate\ local\ context\ makes\ it\ trickier\ to\ \nmaintain\ such\ a\ state\ than\ it\ would\ be\ if\ a\ single\ procedure\ call\ did\ \nall\ the\ work,\ but\ there\ are\ some\ approaches\ one\ can\ use:\n\ \ \ 1.\ Use\ a\ global\ or\ namespace\ variable.\ Inelegant,\ but\ often\ easy\ and\ good\ enough.\n\ \ \ 2.\ Use\ a\ local\ variable\ that\ is\ accessed\ using\ \[upvar\].\ Gets\ into\ trouble\ if\ \[uplevel\]\ or\ \[namespace\ eval\]\ is\ being\ used\ as\ shown\ in\ the\ previous\ section.\n\ \ \ 3.\ Pass\ the\ previous\ state\ as\ a\ command\ argument\ and\ return\ it\ as\ the\ command\ result.\ This\ is\ the\ \[functional\ programming\]\ idiom.\n----\n**Collecting\ children\ in\ a\ sublist\ or\ placing\ them\ directly\ the\ node\ list**\n\nThe\ data\ in\ a\ node\ can\ be\ categorised\ as:\n\ \ \ 1.\ Node\ type.\n\ \ \ 2.\ Annotations\ (data\ not\ in\ the\ form\ of\ a\ node).\n\ \ \ 3.\ Children\ (data\ in\ node\ format).\nIn\ the\ algebraic\ examples\ above,\ the\ '''const'''\ and\ '''var'''\ nodes\ have\ \nannotations\ (value\ and\ variable\ names\ respectively)\ but\ no\ children,\ \nwhereas\ the\ other\ node\ types\ have\ children\ but\ no\ annotations.\nThe\ \[grammar_fa\]\ example\ (see\ bullet\ list\ below)\ is\ similar,\ \nbut\ adds\ the\ complication\ that\ some\ nodes\ can\ have\ an\ \narbitrary\ number\ of\ children.\ In\ the\ \[parsetcl\]\ example,\ \nall\ nodes\ have\ two\ pieces\ of\ annotation\ and\ in\ addition\ many\nhave\ a\ variable\ number\ of\ children.\ Most\ general\ is\ the\ data\ \nstructure\ employed\ by\ \[a\ little\ XML\ parser\],\ since\ a\ typical\ \nnode\ in\ that\ case\ can\ have\ an\ arbitrary\ number\ of\ annotations\ \nand\ an\ arbitrary\ number\ of\ children.\n\nThe\ issue\ considered\ here\ is\ how\ to\ best\ design\ the\ list\ \nstructure\ for\ the\ various\ node\ types.\ If\ the\ number\ of\ \nannotations\ and\ children\ is\ determined\ by\ the\ node\ type,\ then\ \nit\ probably\ seems\ natural\ to\ just\ lay\ them\ out\ in\ a\ flat\ \nstructure\n======\n\ \ nodetype\ annot1\ annot2\ ...\ annotM\ child1\ child2\ ...\ childN\n======\nsince\ it\ is\ then\ trivial\ to\ name\ all\ the\ arguments\ in\ the\ \nproc\ definition\ \n======\n\ \ proc\ \$nodetype\ \{annot1\ annot2\ ...\ annotM\ child1\ child2\ ...\ childN\}\ \{\ #\ ...\n======\n--\ no\ need\ to\ \[lassign\]\ or\ such,\ and\ you\ get\ good\ error\ \nmessages\ for\ free.\n\nIt\ is\ ''possible''\ to\ use\ this\ design\ also\ for\ node\ types\ with\ \na\ variable\ number\ of\ children,\ since\ the\ proc\ definition\ can\ \njust\ as\ easily\ be\n======\n\ \ proc\ \$nodetype\ \{annot1\ annot2\ ...\ annotN\ args\}\ \{\ #\ ...\n======\n(this\ was\ very\ much\ done\ in\ \[parsetcl\]),\ but\ in\ these\ cases\ \nit\ is\ ''better''\ to\ have\ just\ one\ argument\ which\ is\ the\ list\ \nof\ children,\ like\ so:\n======\n\ \ proc\ \$nodetype\ \{annot1\ annot2\ ...\ annotN\ children\}\ \{\ #\ ...\n======\nWhy\ is\ that?\ Because\ it\ simplifies\ operations\ which\ take\ \narguments\ (like\ '''eval2''',\ '''parteval''',\ '''diff''',\ and\ \n'''toexpr'''\ above)!\ Consider\ what\ would\ happen\ if\ +\ nodes\ \nlooked\ like\n\ \ \ \ :\ \ \ '''+'''\ ''?term\ ...?''\n(variadic\ addition\ is\ actually\ more\ natural\ for\ algebra).\ \nThe\ '''eval'''\ operation\ is\ straightforward\n======\n\ \ proc\ algexpr::eval::+\ \{args\}\ \{\n\ \ \ \ \ set\ sum\ 0\n\ \ \ \ \ foreach\ term\ \$args\ \{\n\ \ \ \ \ \ \ \ set\ sum\ \[expr\ \{\$sum\ +\ \[eval\ \$term\]\}\]\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$sum\n\ \ \}\n======\nbut\ the\ '''diff'''\ operation\ is\ much\ trickier\ due\ to\ the\ \nexceptional\ final\ argument\ holding\ the\ differentiation\ \nvariable\ name\n======\n\ \ proc\ algexpr::diff::+\ \{args\}\ \{\n\ \ \ \ \ set\ var\ \[lindex\ \$args\ end\]\n\ \ \ \ \ set\ res\ \[list\ +\]\n\ \ \ \ \ foreach\ term\ \[lrange\ \$args\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ lappend\ res\ \[eval\ \$term\ \[list\ \$var\]\]\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$res\n\ \ \}\n======\nand\ the\ '''eval2'''\ operation\ is\ simply\ impossible\ --\ there\ \nis\ no\ sure\ way\ to\ distinguish\ variable-value\ arguments\ from\ \nchild\ node\ arguments.\n\nThis\ problem\ does\ not\ arise\ if\ the\ syntax\ had\ instead\ been\ \n\ \ \ \ :\ \ \ '''sum'''\ ''term-list''\n(the\ '''+'''\ node\ type\ is\ already\ assigned\ to\ binary\ addition)\ since\ \nthe\ implementations\ are\ then\ \n======\n\ \ proc\ algexpr::diff::sum\ \{terms\ var\}\ \{\n\ \ \ \ \ set\ res\ \[list\ sum\]\n\ \ \ \ \ foreach\ term\ \$terms\ \{\n\ \ \ \ \ \ \ \ lappend\ res\ \[eval\ \$term\ \[list\ \$var\]\]\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$res\n\ \ \}\n\ \ proc\ algexpr::eval2::sum\ \{terms\ args\}\ \{\n\ \ \ \ \ set\ sum\ 0\n\ \ \ \ \ foreach\ term\ \$terms\ \{\n\ \ \ \ \ \ \ \ set\ sum\ \[expr\ \{\$sum\ +\ \[eval\ \$term\ \$args\]\}\]\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$sum\n\ \ \}\n======\n\[A\ little\ XML\ parser\]\ has\ got\ this\ right,\ with\ one\ argument\ \nthat\ is\ a\ dictionary\ of\ annotations\ and\ another\ that\ is\ the\ \nlist\ of\ children.\ After\ that\ can\ follow\ any\ number\ of\ operation\ \narguments,\ and\ it\ is\ easy\ to\ see\ which\ is\ which.\n\nStill,\ it\ sometimes\ happens\ that\ one\ has\ to\ implement\ operations\ \non\ data\ in\ a\ legacy\ format,\ with\ the\ list\ of\ children\ expanded\ \ninto\ the\ node\ list.\ What\ can\ one\ do\ then?\ One\ possibility\ is\ to\ \nfirst\ implement\ an\ operation\ converting\ the\ data\ to\ a\ child-list\ \nformat,\ because\ that\ operation\ doesn't\ need\ arguments,\ and\ then\ \nperform\ the\ wanted\ operation\ on\ the\ converted\ data.\ Another\ \npossibility\ is\ to\ design\ the\ argument\ structure\ for\ the\ operation\ \nso\ that\ there\ is\ an\ explicit\ end-of-children\ argument,\ like\ --\ \nto\ signal\ end\ of\ switches.\ In\ this\ case,\ the\ right\ form\ of\ an\ \nend-of-children\ argument\ is\ an\ empty\ list,\ since\ every\ child\ \nmust\ be\ a\ list\ of\ length\ at\ least\ 1.\ In\ that\ case,\ one\ could\ \ndefine\n======\n\ \ proc\ algexpr::eval3::+\ \{args\}\ \{\n\ \ \ \ \ set\ n\ 0\n\ \ \ \ \ foreach\ term\ \$args\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$term\]\ <\ 1\}\ then\ \{break\}\n\ \ \ \ \ \ \ \ incr\ n\n\ \ \ \ \ \}\n\ \ \ \ \ set\ sum\ 0\n\ \ \ \ \ foreach\ term\ \[lreplace\ \$args\ \$n\ end\]\ \{\n\ \ \ \ \ \ \ \ set\ sum\ \[expr\ \{\$sum\ +\ \[eval\ \$term\ \[lrange\ \$args\ \$n\ end\]\]\}\]\n\ \ \ \ \ \}\n\ \ \ \ \ return\ \$sum\n\ \ \}\n======\nand\ make\ calls\ like\n======\n\ \ namespace\ inscope\ algexpr::eval3\ \$datum\ \{\}\ x\ 1\n======\nbut\ the\ need\ for\ the\ extra\ end-of-children\ argument\ means\ this\ \nis\ not\ the\ same\ operation\ as\ '''eval2'''.\n\n----\n**Discussion**\n\n\[male\]\ -\ 2007-03-12:\n\nThanks\ for\ your\ very\ detailed\ \[data\ is\ code\]\ page!\n\nMy\ best\ example\ for\ \[data\ is\ code\]\ was\ my\ way\ to\ read\ VRML\ files,\ to\ import\ their\ structure\ and\ their\ geometrical\ data:\n\n\ \ \ 1.\ Read\ the\ file\ data\n\ \ \ 2.\ Convert\ the\ file\ data\ to\ a\ valid\ list\n\ \ \ 3.\ Reorganize\ the\ file\ data\ list\ to\ have\ all\ VRML\ node\ attributes\ in\ sub\ lists\n\ \ \ 4.\ Evaluate\ this\ list\ with\ the\ scheme,\ that\ each\ VRML\ node\ name\ could\ be\ the\ name\ of\ a\ tcl\ command\ or\ procedure.\ If\ such\ a\ tcl\ procedure\ exists,\ than\ evaluate\ it\ with\ the\ VRML\ node\ attributes\ as\ arguments,\ if\ not\ ignore\ this\ VRML\ node.\n\nSuch\ becomes\ VRML\ data\ executable\ code.\n\n----\n\[NEM\]\ ''12\ Mar\ 2007'':\ Thanks,\ Lars,\ this\ is\ a\ useful\ technique\ to\ document.\ I've\ only\ skimmed\ at\npresent,\ so\ apologies\ if\ some\ of\ these\ remarks\ are\ covered.\ An\ alternative\ to\ using\ a\ namespace\nwould\ be\ to\ just\ use\ a\ \[switch\]\ (or\ some\ form\ of\ \[pattern\ matching\])\ inside\ a\ proc.\ For\ instance,\nthe\ first\ expression\ evaluator\ might\ be\ written:\n======\n\ proc\ algexpr::calc\ expr\ \{\ \ \ \ \ \ \ \ \ \n\ \ \ \ lassign\ \$expr\ op\ a\ b\n\ \ \ \ switch\ -exact\ --\ \$op\ \{\n\ \ \ \ \ \ \ \ +\ \ \ \ \ \{\ expr\ \{\[calc\ \$a\]\ +\ \[calc\ \$b\]\}\ \}\n\ \ \ \ \ \ \ \ -\ \ \ \ \ \{\ expr\ \{\[calc\ \$a\]\ -\ \[calc\ \$b\]\}\ \}\n\ \ \ \ \ \ \ \ *\ \ \ \ \ \{\ expr\ \{\[calc\ \$a\]\ *\ \[calc\ \$b\]\}\ \}\n\ \ \ \ \ \ \ \ /\ \ \ \ \ \{\ expr\ \{\[calc\ \$a\]\ /\ double(\[calc\ \$b\])\}\ \}\n\ \ \ \ \ \ \ \ const\ \{\ return\ \$a\ \}\n\ \ \ \ \ \ \ \ var\ \ \ \{\ upvar\ #0\ \$a\ v\;\ return\ \$v\ \}\n\ \ \ \ \}\ \ \ \ \ \n\ \}\n======\nA\ sugared\ version\ of\ this\ appears\ in\ \[a\ lambda\ calculus\ interpreter\ with\ arithmetic\].\n\n''\[Lars\ H\]:\ The\ only\ catch\ in\ that\ is\ that\ it\ doesn't\ really\ do\ \[data\ is\ code\],\ as\ the\ data\ isn't\ treated\ as\ code\;\ in\ a\ sense,\ it\ is\ precisely\ the\ more\ traditional\ technique\ that\ data-is-code\ provides\ an\ alternative\ to!''\n\n\[NEM\]:\ Right,\ but\ what\ are\ the\ advantages\ of\ manipulating\ data\ as\ Tcl\ code\ as\ opposed\ to\ just\ntreating\ it\ as\ a\ bit\ of\ data?\ Speed?\ Leveraging\ the\ existing\ Tcl\ interpreter\ code?\ The\ above\nproc\ is\ a\ bare-bones\ interpreter\ for\ a\ minimal\ language\ of\ arithmetic\ expressions,\ so\ its\ data\nis\ also\ code.\ Code\ ''is''\ just\ data,\ after\ all.\ (The\ \"real\"\ dichotomy\ would\ be\ between\ data\ and\nprocesses,\ where\ code\ could\ be\ seen\ as\ data\ that\ describes\ a\ process).\n\n\[Lars\ H\]:\ Speed\ and\ leveraging\ existing\ mechanisms\ are\ indeed\ reasons\ why\ this\ is\ useful.\ Another\ reason\ is\ extensionality\ (how\ do\ you\ tell\ algexpr::calc\ about\ the\ '''exp'''\ node\ type?).\ As\ for\ \"\[code\ is\ data\]\"...\ well,\ that\ would\ be\ the\ subject\ of\ another\ page\ (every\ now\ and\ then\ I\ mix\ the\ two\ up\ too).\n\n\[NEM\]:\ Code\ really\ is\ just\ data...\ But\ anyway,\ to\ the\ other\ points:\ I'm\ not\ so\ sure\ about\ the\nspeed,\ although\ I'm\ prepared\ to\ believe\ it\ for\ more\ complex\ examples.\ For\ example,\ transforming\nXML\ data\ into\ Tcl\ code\ could\ result\ in\ a\ quite\ fast\ parser,\ but\ it's\ tricky\ to\ do\ correctly,\ and\nthere\ are\ of\ course\ issues\ with\ trust\ --\ Tcl\ is\ a\ much\ more\ powerful\ language\ than\ a\ custom\nlittle\ interpreter.\ As\ to\ the\ question\ of\ extensibility,\ it\ is\ actually\ fairly\ simple\ to\ extend\na\ switch-based\ interpreter\ without\ altering\ the\ original\ with\ a\ little\ forethought.\ All\ you\ \nneed\ to\ do\ is\ to\ use\ open-recursion\ and\ an\ explicit\ fixpoint\ operator\ (here\ we\nadd\ support\ for\ environments\ too\;\ \[dict\]\ required):\n======\n\ proc\ calc\ \{self\ expr\ env\}\ \{\n\ \ \ \ \ lassign\ \$expr\ op\ a\ b\n\ \ \ \ \ switch\ -exact\ --\ \$op\ \{\n\ \ \ \ \ \ \ \ \ +\ \ \ \ \ \ \ \{\ expr\ \{\[call\ \$self\ \$a\ \$env\]\ +\ \[call\ \$self\ \$b\ \$env\]\}\ \}\n\ \ \ \ \ \ \ \ \ -\ \ \ \ \ \ \ \{\ expr\ \{\[call\ \$self\ \$a\ \$env\]\ -\ \[call\ \$self\ \$b\ \$env\]\}\ \}\n\ \ \ \ \ \ \ \ \ *\ \ \ \ \ \ \ \{\ expr\ \{\[call\ \$self\ \$a\ \$env\]\ *\ \[call\ \$self\ \$b\ \$env\]\}\ \}\n\ \ \ \ \ \ \ \ \ /\ \ \ \ \ \ \ \{\ expr\ \{\[call\ \$self\ \$a\ \$env\]\ /\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double(\[call\ \$self\ \$b\ \$env\])\}\ \}\n\ \ \ \ \ \ \ \ \ const\ \ \ \{\ return\ \$a\ \}\n\ \ \ \ \ \ \ \ \ var\ \ \ \ \ \{\ dict\ get\ \$env\ \$a\ \}\n\ \ \ \ \ \ \ \ \ default\ \{\ error\ \"unknown\ op\ \\\"\$op\\\"\"\ \}\n\ \ \ \ \ \}\n\ \}\n\ #\ fixpoint\ operator\ (similar\ to\ Y\ combinator):\n\ proc\ call\ \{cmd\ args\}\ \{\ uplevel\ #0\ \$cmd\ \[linsert\ \$args\ 0\ \$cmd\]\ \}\n======\nWe\ can\ then\ call\ our\ command\ using\ the\ fixpoint\ operator\ (which\ is\ quite\ similar\ in\ some\ ways\ to\n\[TOOT\]\ dispatch):\n======\n\ %\ set\ datum\ \{/\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\}\n\ /\ \{-\ \{*\ \{const\ 2\}\ \{var\ x\}\}\ \{const\ 1\}\}\ \{+\ \{var\ x\}\ \{const\ 3\}\}\n\ %\ call\ calc\ \$datum\ \{x\ 1\}\n\ 0.25\n======\nExtending\ the\ language\ to\ support\ an\ ''exp''\ operation\ is\ now\ a\ simple\ task,\ much\ like\nextending\ an\ OO\ program:\n======\n\ proc\ calcexp\ \{self\ expr\ env\}\ \{\n\ \ \ \ \ lassign\ \$expr\ op\ arg\n\ \ \ \ \ switch\ -exact\ --\ \$op\ \{\n\ \ \ \ \ \ \ \ \ exp\ \ \ \ \ \{\ expr\ \{exp(\[call\ \$self\ \$arg\ \$env\])\}\ \}\n\ \ \ \ \ \ \ \ \ default\ \{\ calc\ \$self\ \$expr\ \$env\ \}\n\ \ \ \ \ \}\n\ \}\n======\nAnd\ to\ test:\n======\n\ %\ set\ datum3\ \{exp\ \{/\ \{var\ x\}\ \{var\ y\}\}\}\n\ exp\ \{/\ \{var\ x\}\ \{var\ y\}\}\n\ %\ call\ calcexp\ \$datum3\ \{x\ 2\ y\ 1\}\n\ 7.38905609893065\n======\nNote\ that\ our\ original\ language\ is\ still\ available,\ so\ only\ those\ callers\ who\ want\ the\ extended\nlanguage\ have\ to\ get\ it:\n======\n\ %\ call\ calc\ \$datum3\ \{x\ 2\ y\ 1\}\n\ unknown\ op\ \"exp\"\n======\n\n\[NEM\]\ (A\ few\ minutes\ later):\ It's\ also\ quite\ simple\ to\ extend\ the\ language\ in\ different\ directions.\nFor\ example\ (and\ because\ it's\ fun!),\ here's\ how\ to\ add\ lexically-scoped\ \[lambda\]\ expressions\ to\nthe\ language\ (something\ Tcl\ itself\ doesn't\ have\ built-in):\n======\n\ proc\ calclam\ \{self\ expr\ env\}\ \{\n\ \ \ \ \ lassign\ \$expr\ op\ a\ b\n\ \ \ \ \ switch\ -exact\ --\ \$op\ \{\n\ \ \ \ \ \ \ \ \ lambda\ \ \{\ list\ closure\ \$a\ \$b\ \$env\ \}\n\ \ \ \ \ \ \ \ \ app\ \ \ \ \ \{\ calcapp\ \$self\ \[call\ \$self\ \$a\ \$env\]\ \[call\ \$self\ \$b\ \$env\]\ \}\n\ \ \ \ \ \ \ \ \ default\ \{\ calc\ \$self\ \$expr\ \$env\ \}\n\ \ \ \ \ \}\n\ \}\n\ proc\ calcapp\ \{self\ f\ x\}\ \{\n\ \ \ \ \ lassign\ \$f\ op\ arg\ body\ env\n\ \ \ \ \ switch\ -exact\ --\ \$op\ \{\n\ \ \ \ \ \ \ \ \ closure\ \{\ call\ \$self\ \$body\ \[dict\ replace\ \$env\ \$arg\ \$x\]\ \}\n\ \ \ \ \ \ \ \ \ default\ \{\ error\ \"not\ a\ closure:\ \\\"\$f\\\"\"\ \}\n\ \ \ \ \ \}\n\ \}\n======\nAnd\ the\ test:\n======\n\ %\ set\ f\ \{lambda\ x\ \{lambda\ y\ \{*\ \{var\ x\}\ \{var\ y\}\}\}\}\n\ lambda\ x\ \{lambda\ y\ \{*\ \{var\ x\}\ \{var\ y\}\}\}\n\ %\ set\ exp\ \[list\ app\ \[list\ app\ \$f\ \{const\ 3\}\]\ \{const\ 4\}\]\n\ app\ \{app\ \{lambda\ x\ \{lambda\ y\ \{*\ \{var\ x\}\ \{var\ y\}\}\}\}\ \{const\ 3\}\}\ \{const\ 4\}\n\ %\ call\ calclam\ \$exp\ \{\}\ \n\ 12\n======\n----\n\[NEM\]\ ''(cont.)''\ As\ you\ mention\ at\ the\ start,\ an\ \[OO\]\ approach\ makes\ it\ easy\ to\ add\ new\ types\ (just\ add\ a\ new\nsub-class\ and\ implement\ the\ operations),\ but\ trickier\ to\ add\ new\ operations,\ whereas\ a\ pattern\nmatching\ approach\ makes\ it\ easier\ to\ add\ new\ operations\ but\ harder\ to\ add\ new\ data\ types\ (as\nyou\ need\ to\ update\ all\ the\ operations).\ This\ is\ apparently\ known\ as\ the\ ''expression\ problem''\nin\ programming\ language\ design,\ and\ there\ are\ a\ number\ of\ ways\ in\ which\ it\ is\ tackled.\ The\nusual\ OO\ way\ is\ the\ \[Visitor\ pattern\],\ which\ essentially\ implements\ pattern\ matching\ over\nOO\ dispatch.\ In\ this\ case\ you'd\ have\ something\ like\ the\ following\ (psuedo-code):\n======\n\ class\ Expr\ \{\n\ \ \ \ \ abstract\ method\ visit\ \{visitor\}\n\ \}\n\ class\ Num\ val\ \{\n\ \ \ \ \ inherit\ Expr\n\ \ \ \ \ method\ visit\ \{visitor\}\ \{\ \$visitor\ visitNum\ \$val\ \}\n\ \}\n\ class\ AddOp\ a\ b\ \{\n\ \ \ \ \ inherit\ Expr\n\ \ \ \ \ method\ visit\ \{visitor\}\ \{\ \$visitor\ visitAddOp\ \$a\ \$b\ \}\n\ \}\n\ ...\n\ class\ ExprVisitor\ \{\n\ \ \ \ \ abstract\ method\ visitNum\ \{val\}\n\ \ \ \ \ abstract\ method\ visitAddOp\ \{a\ b\}\n\ \ \ \ \ ...\n\ \}\n\ class\ ExprInterp\ \{\n\ \ \ \ \ inherit\ ExprVisitor\n\ \ \ \ \ method\ visitNum\ \{val\}\ \{\ return\ \$val\ \}\n\ \ \ \ \ method\ visitAddOp\ \{a\ b\}\ \{\ expr\ \{\[\$a\ visit\ \$self\]\ +\ \[\$b\ visit\ \$self\]\}\ \}\n\ \ \ \ \ ...\n\ \}\n\ \[AddOp\ \[AddOp\ \[Num\ 2\]\ \[Num\ 5\]\]\ \[Num\ 4\]\]\ visit\ \[ExprInterp\]\ \;#\ =>\ 11\n======\nPattern\ matching\ can\ also\ be\ made\ more\ flexible\ by\ including\ default\ cases.\n\n----\n\n\[LV\]\ One\ of\ the\ examples\ I've\ read\ about,\ in\ terms\ of\ this\ topic,\ has\ to\ do\nwith\ saving\ the\ state\ of\ a\ Tcl\ program.\ The\ idea\ is\ that\ one\ would\ write\n\[proc\]s\ which\ would\ go\ through\ and\ save\ off\ the\ values\ of\ any\ variable,\nproc,\ namespace,\ etc.\ At\ first,\ I\ thought\ ''well,\ only\ the\ values\ which\nare\ dynamically\ set\ are\ necessary\ -\ the\ procs\ defined\ in\ the\ program's\nfile\ itself\ need\ not\ be\ saved,\ nor\ variables\ which\ are\ set\ within\ that\ file.''\nHowever,\ given\ that\ someone\ might\ come\ along\ and\ modify\ the\ program,\ or\nfor\ that\ matter,\ given\ that\ you\ would\ have\ to\ write\ specialized\ code\nto\ avoid\ getting\ those\ values,\ it\ is\ much\ easier\ just\ to\ save\ everything.\nIf\ done\ properly,\ the\ \"save\ file\"\ should\ be\ able\ to\ be\ invoked\ and\ the\napplication\ would\ be\ back\ the\ way\ things\ were\ (with\ some\ possible\nexceptions,\ depending\ on\ the\ code,\ extensions,\ etc.)\ when\ last\ started.\n\n----\n**See\ also**\n\nExamples\ found\ \"in\ the\ wild\"\ of\ data\ structures\ which\ support\ the\ data-is-code\ paradigm:\n\ \ \ \[parsetcl\]:\ \ \ Represents\ the\ syntactic\ structure\ of\ Tcl\ code\ as\ a\ list-tree.\ A\ wiki\ user\ contributed\ a\ set\ of\ procs\ that\ made\ the\ list-tree\ convert\ itself\ back\ to\ Tcl\ code\ when\ evaluated!\n\ \ \ \[grammar_fa\]:\ \ \ Has\ a\ list-tree\ representation\ for\ regular\ expressions.\ Node\ types\ are\ '''S''',\ '''.''',\ '''|''',\ '''&''',\ '''*''',\ '''?''',\ '''+''',\ and\ '''!'''.\n\ \ \ \[A\ little\ XML\ parser\]:\ \ \ Has\ tree-list\ representation\ (inherited\ from\ \[tdom\])\ for\ XML\ data.\ Node\ types\ are\ the\ tags\ that\ may\ occur,\ and\ #text\ for\ text\ content.\n\ \ \ \[Geometry\]:\ \ \ Represents\ geometric\ objects\ as\ list-trees,\ with\ POINT\ and\ VECTOR\ as\ leaf\ node\ types.\n\nGoing\ one\ step\ further:\ \[code\ is\ data\ is\ code\]\n----\n''\[escargo\]\ 4\ Nov\ 2008''\ -\ And\ here\ I\ thought\ the\ word\ \"data\"\ is\ plural.\ \n\n\[NEM\]:\ Singular\ or\ plural.\ \"Data\ are\ codes\"\ sounds\ weird.\n\n<<categories>>\ Concept\ |\ Control\ Structure\ |\ Data\ Structure\ |\ Design\ |\ Mathematics\ |\ Tutorial} CALL {my revision {data is code}} CALL {::oo::Obj5867398 process revision/data+is+code} CALL {::oo::Obj5867396 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4