{"id":430182,"date":"2024-08-25T15:00:09","date_gmt":"2024-08-25T15:00:09","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=430182"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=430182","title":{"rendered":"<span>\u0422\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 eDSL \u043d\u0430 Go<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e, \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 DSL \u043d\u0430 Go. \u0420\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c, \u0442.\u0435. \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0441\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f (\u0442\u0435\u0440\u043c\u044b), \u043d\u043e \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u0442\u0438\u043f\u043e\u0432 DSL \u043e\u0434\u0438\u043d-\u043a-\u043e\u0434\u043d\u043e\u043c\u0443 \u043c\u0430\u043f\u043f\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0442\u0438\u043f\u043e\u0432 Go, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0435\u0441\u044c type-checking \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u043e\u043c.<\/p>\n<p>\u041e\u0431\u044b\u0447\u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f <abbr class=\"habraabbr\" title=\"\u041e\u0431\u043e\u0431\u0449\u0435\u043d\u043d\u044b\u0435 \u0430\u043b\u0433\u0435\u0431\u0440\u0430\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445\" data-title=\"&lt;p&gt;\u041e\u0431\u043e\u0431\u0449\u0435\u043d\u043d\u044b\u0435 \u0430\u043b\u0433\u0435\u0431\u0440\u0430\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445&lt;\/p&gt;&lt;p&gt;&lt;\/p&gt;\" data-abbr=\"GADT\">GADT<\/abbr> \u0438\u043b\u0438 <abbr class=\"habraabbr\" title=\"Higher-kinded types - \u0442\u0438\u043f\u044b \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430\" data-title=\"&lt;p&gt;Higher-kinded types - \u0442\u0438\u043f\u044b \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430&lt;\/p&gt;&lt;p&gt;&lt;\/p&gt;\" data-abbr=\"HKT\">HKT<\/abbr>. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043d\u0438 \u043e\u0442 \u043f\u0435\u0440\u0432\u043e\u0433\u043e, \u043d\u0438 \u043e\u0442 \u0432\u0442\u043e\u0440\u043e\u0433\u043e.<\/p>\n<p>\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Universal_quantification\" rel=\"noopener noreferrer nofollow\">\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e<\/a> \u043a\u0432\u0430\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Boehm-Berarducci <a href=\"#sources\" rel=\"noopener noreferrer nofollow\">[1]<\/a> \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <a href=\"https:\/\/en.wikipedia.org\/wiki\/Existential_quantification\" rel=\"noopener noreferrer nofollow\">\u044d\u043a\u0437\u0438\u0441\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0435<\/a> \u043a\u0432\u0430\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 (\u0431\u0435\u0437 \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u0438 \u0432 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u0438\u0437\u043c\u0435 \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u0437\u0430 \u0441\u0447\u0435\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u044d\u043a\u0437\u0438\u0441\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0442\u0438\u043f\u0430\u043c\u0438).<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041f\u0440\u043e \u044d\u043a\u0437\u0438\u0441\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0441\u043c. <a href=\"https:\/\/sources\" rel=\"noopener noreferrer nofollow\">[2]<\/a><\/p>\n<\/div>\n<\/details>\n<p>\u041a\u0430\u043a \u0438 \u0430\u043b\u0433\u0435\u0431\u0440\u0430\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043a\u0440\u044b\u0442\u043e (\u043d\u0435\u043b\u044c\u0437\u044f \u0431\u0435\u0437 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043e\u0434\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 statement), \u043d\u043e \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d-\u043c\u0430\u0442\u0447\u0438\u043d\u0433\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u043f\u043e\u043b\u043d\u043e\u0442\u0443 \u0432 compile-time. \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0435 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 GADT \u0432 \u0441\u0442\u0438\u043b\u0435 Tagless-final \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0435 \u0442\u0435\u0440\u043c\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 Go \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438, \u043d\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0435 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u044e\u0442\u0441\u044f. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u043a\u0440\u044b\u0442\u043e\u0441\u0442\u044c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440 \u0432 \u043f\u043e\u043b\u044c\u0437\u0443 \u0431\u043e\u043b\u044c\u0448\u0435\u0439 type-safety, \u043d\u043e \u043f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0448\u0438\u0442\u044c <a href=\"https:\/\/en.wikipedia.org\/wiki\/Expression_problem\" rel=\"noopener noreferrer nofollow\">expression problem<\/a>.<\/p>\n<p>\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 GADT (\u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430 Haskell):<\/p>\n<pre><code class=\"haskell\">data Exp a where     Lit :: a -&gt; Exp a     Add :: Exp Int -&gt; Exp Int -&gt; Exp Int     Or  :: Exp Bool -&gt; Exp Bool -&gt; Exp Bool     Lt  :: Exp Int -&gt; Exp Int -&gt; Exp Bool     If  :: Exp Bool -&gt; Exp a -&gt; Exp a -&gt; Exp a<\/code><\/pre>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f DSL<\/h2>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 Exp \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c eDSL. \u041c\u0435\u0442\u043e\u0434 MatchExp \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0435\u0442 ADT \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. ExpBoolVars \u0438 ExpIntVars \u044d\u0442\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0439 (<a href=\"https:\/\/en.wikipedia.org\/wiki\/Continuation\" rel=\"noopener noreferrer nofollow\">continuations<\/a>). \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f ExpKind \u0441\u0442\u0440\u043e\u0433\u043e \u0433\u043e\u0432\u043e\u0440\u044f \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u0435\u043d \u0434\u043b\u044f \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u0442\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u0435\u0439 \u0441\u043e\u043e\u0431\u0449\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0435 \u0438\u0437 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0439 \u0431\u044b\u043b\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<pre><code class=\"go\">type Exp interface { MatchExp(ExpBoolVars, ExpIntVars) ExpKind }<\/code><\/pre>\n<p>\u0412\u0432\u0435\u0434\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043e\u0441\u0442\u044b\u043b\u044c, \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 <code>ety<\/code> \u0434\u043b\u044f \u0434\u0435\u043d\u043e\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u0438 DSL<\/p>\n<pre><code class=\"go\">type ety interface { bool | int }<\/code><\/pre>\n<p><code>exp[t]<\/code> &#8212; \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f DSL-\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 t, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u0430\u043f\u043f\u0438\u0442\u0441\u044f \u043d\u0430 Go-\u0442\u0438\u043f t. \u041d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u044b\u043c \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 Exp. \u041f\u0440\u0438\u0447\u0438\u043d\u0430 \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u044c Exp, \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c \u0447\u0442\u043e t \u044d\u0442\u043e \u0444\u0430\u043d\u0442\u043e\u043c\u043d\u044b\u0439 \u0442\u0438\u043f (\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 compile-time \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0438\u043f\u043e\u0432). \u041a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0435\u0441\u0442\u0435\u0433\u043e\u0432\u043e\u0435 (tagless), \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0437\u0430 \u044d\u043a\u0437\u0438\u0441\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u043e\u043c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u0435\u0442\u0435\u0440\u043e\u0433\u0435\u043d\u043d\u044b\u0435 \u0441\u043f\u0438\u0441\u043a\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439.<\/p>\n<pre><code class=\"go\">type exp[t ety] interface { Exp }<\/code><\/pre>\n<p><code>ExpBoolVars, ExpIntVars<\/code> \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0446\u0438\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u0432 ADT. \u0427\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u0442\u0438\u043f\u043e\u0432 \u0443 DSL \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c. \u0417\u0434\u0435\u0441\u044c \u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e, \u043d\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u0432\u0441\u0435 \u0435\u0449\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u043c\u0438.<\/p>\n<pre><code class=\"go\">\/\/ \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0431\u0443\u043b\u0435\u0432\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 type ExpBoolVars interface { Lit(bool) Or(exp[bool], exp[bool]) Lt(exp[int], exp[int]) If(exp[bool], exp[bool], exp[bool]) }  \/\/ \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f int \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 type ExpIntVars interface { Lit(int) Add(exp[int], exp[int]) If(exp[bool], exp[int], exp[int]) }<\/code><\/pre>\n<p><code>ExpKind<\/code> \u0435\u0449\u0435 \u043e\u0434\u0438\u043d ADT \u043d\u0443\u0436\u043d\u044b\u0439 \u0447\u0442\u043e\u0431\u044b \u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u0438\u0445 \u0442\u0438\u043f\u0430\u043c. <code>KindVars<\/code> &#8212; \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"go\">type ExpKind interface { MatchKind(KindVars) }  type KindVars interface { Bool(ExpBoolVars) Int(ExpIntVars) }<\/code><\/pre>\n<p><code>boolVal, intVal<\/code> \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 ExpKind.<\/p>\n<pre><code class=\"go\">type boolVal struct{ ev ExpBoolVars } type intVal struct{ ev ExpIntVars }  func (b boolVal) MatchKind(v KindVars) { v.Bool(b.ev) } func (n intVal) MatchKind(v KindVars)  { v.Int(n.ev) }<\/code><\/pre>\n<p><code>MatchIntExp, MatchBoolExp<\/code> &#8212; \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u0442\u0435\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443\u0436\u0435 \u0437\u043d\u0430\u0435\u043c \u0438\u0445 \u0442\u0438\u043f.<\/p>\n<pre><code class=\"go\">func MatchIntExp[tv ExpIntVars](e exp[int], v tv) tv { e.MatchExp(nil, v) return v }  func MatchBoolExp[tv ExpBoolVars](e exp[bool], v tv) tv { e.MatchExp(v, nil) return v }<\/code><\/pre>\n<p><code>lit[t], add, or, lt, if_<\/code> \u043a\u043e\u0434\u0438\u0440\u0443\u044e\u0442 \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0415\u0441\u043b\u0438 ADT \u044d\u0442\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435, \u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u0443\u0442\u043e\u0447\u043d\u044f\u0435\u043c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439.<\/p>\n<pre><code class=\"go\">type lit[t ety] struct{ val t } type add struct{ a, b exp[int] } type or struct{ a, b exp[bool] } type lt struct{ a, b exp[int] } type if_[t ety] struct { c exp[bool] t exp[t] f exp[t] }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b <code>MatchExp<\/code> \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442 <code>exp[t]<\/code>. \u041a\u0430\u0436\u0434\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f, \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0438\u0445. \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c switch \u043f\u043e \u0442\u0438\u043f\u0430\u043c \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043e\u0439\u0442\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f Go \u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u0432\u0430\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 Go \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u044c \u0447\u0442\u043e \u043d\u0430\u0431\u043e\u0440 case \u0432\u0435\u0442\u043e\u043a \u043f\u043e\u043b\u043e\u043d (exhaustive) \u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u044c default. \u041d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f DSL \u043d\u0438\u043a\u0430\u043a\u0438\u0445 switch \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f.<\/p>\n<pre><code class=\"go\">func (l lit[t]) MatchExp(bv ExpBoolVars, nv ExpIntVars) ExpKind { switch v := interface{}(l).(type) { case lit[bool]: bv.Lit(bool(v.val)) return boolVal{bv} case lit[int]: nv.Lit(int(v.val)) return intVal{nv} default: panic(\"unreachable\") } } func (n add) MatchExp(_ ExpBoolVars, v ExpIntVars) ExpKind { v.Add(n.a, n.b) return intVal{v} } func (b or) MatchExp(v ExpBoolVars, _ ExpIntVars) ExpKind { v.Or(b.a, b.b) return boolVal{v} } func (b lt) MatchExp(v ExpBoolVars, _ ExpIntVars) ExpKind { v.Lt(b.a, b.b) return boolVal{v} } func (e if_[t]) MatchExp(bv ExpBoolVars, nv ExpIntVars) ExpKind { switch interface{}(*new(t)).(type) { case bool: bv.If(e.c, e.t.(exp[bool]), e.f.(exp[bool])) return boolVal{bv} case int: nv.If(e.c, e.t.(exp[int]), e.f.(exp[int])) return intVal{nv} default: panic(\"unreachable\") } }<\/code><\/pre>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c <code>fmt.Stringer<\/code> \u0434\u043b\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439.<\/p>\n<pre><code class=\"go\">func (l lit[t]) String() string { return fmt.Sprintf(\"(lit %v)\", l.val) } func (n add) String() string    { return fmt.Sprintf(\"(add %v %v)\", n.a, n.b) } func (b or) String() string     { return fmt.Sprintf(\"(or %v %v)\", b.a, b.b) } func (b lt) String() string     { return fmt.Sprintf(\"(lt %v %v)\", b.a, b.b) } func (e if_[t]) String() string { return fmt.Sprintf(\"(if %v %v %v)\", e.c, e.t, e.f) }<\/code><\/pre>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043a\u0430\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0434\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0442\u0438\u043f\u044b \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u044b\u0432\u043e\u0434 \u0442\u0438\u043f\u043e\u0432 \u0432 Go \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043b\u0443\u0447\u0448\u0435 \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u044d\u0442\u043e \u0432\u0441\u0435 \u0435\u0449\u0435 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u043b\u044f <code>If<\/code>, \u0447\u0442\u043e \u0443\u0434\u0440\u0443\u0447\u0430\u0435\u0442. \u0415\u0441\u043b\u0438 \u0431\u044b Go \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0432\u044b\u0432\u043e\u0434 \u0442\u0438\u043f\u043e\u0432 \u043f\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0443 \u0425\u0438\u043d\u0434\u043b\u0438 &#8212; \u041c\u0438\u043b\u043d\u0435\u0440\u0430, \u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0431\u044b \u043d\u0435 \u0431\u044b\u043b\u043e.<\/p>\n<pre><code class=\"go\">func Lit[t ety](v t) lit[t] { return lit[t]{v} } func Add(a, b exp[int]) add { return add{a, b} } func Or(a, b exp[bool]) or  { return or{a, b} } func Lt(a, b exp[int]) lt   { return lt{a, b} } func If[t ety](c exp[bool], tr, fl exp[t]) if_[t] { return if_[t]{c, tr, fl} }<\/code><\/pre>\n<h2>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 DSL<\/h2>\n<p>\u0412\u0441\u0435 \u0447\u0442\u043e \u0431\u044b\u043b\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043e \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0431\u044b\u043b\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439. \u0414\u0430\u043b\u0435\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f DSL. \u041c\u044b \u0445\u043e\u0442\u0438\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u044e ADT \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u0430 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0448\u0430\u0433\u0430 (<a href=\"https:\/\/en.wikipedia.org\/wiki\/Operational_semantics#Big-step_semantics\" rel=\"noopener noreferrer nofollow\">big-step<\/a>). \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u0438 &#8212; \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043d\u0435 \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440. \u041a\u0430\u043a \u043f\u0440\u0438\u043c\u0435\u0440 \u043c\u044b \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u044e \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442 \u0432 native \u043a\u043e\u0434.<\/p>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u044e eval.<\/p>\n<p><code>EvalInt<\/code> \u044d\u0442\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0432\u0437\u0430\u0438\u043c\u043d\u043e \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0442\u0438\u043f\u0430 int. <code>EvalInt<\/code> \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 <code>ExpIntVars<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0432\u0441\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f (\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u043f\u0430\u0442\u0442\u0435\u0440\u043d-\u043c\u0430\u0442\u0447\u0438\u043d\u0433\u0430), \u0430 \u0438\u043d\u0430\u0447\u0435 \u043a\u043e\u0434 \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f. \u041f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c <code>EvalBool<\/code>.<\/p>\n<pre><code class=\"go\">type EvalInt int type EvalBool bool  func (ev *EvalInt) Lit(n int) { *ev = EvalInt(n) } func (ev *EvalInt) Add(a, b exp[int]) { *ev = evalInt(a) + evalInt(b) } func (ev *EvalInt) If(c exp[bool], t, f exp[int]) { if evalBool(c) { *ev = evalInt(t) return } *ev = evalInt(f) }  func evalInt(e exp[int]) EvalInt { \/\/ \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0437\u043d\u0430\u0435\u0442, \u0447\u0442\u043e \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 exp[int], \/\/ \u0442\u0430\u043a \u0447\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u044b\u0437\u0432\u0430\u0442\u044c MatchBoolExp \u043f\u043e \u043e\u0448\u0438\u0431\u043a\u0435. return *MatchIntExp(e, new(EvalInt)) }  func (ev *EvalBool) Lit(b bool) { *ev = EvalBool(b) } func (ev *EvalBool) Or(a, b exp[bool]) { *ev = evalBool(a) || evalBool(b) } func (ev *EvalBool) Lt(a, b exp[int]) { if evalInt(a) &lt; evalInt(b) { *ev = EvalBool(true) return } *ev = EvalBool(false) } func (ev *EvalBool) If(c, t, f exp[bool]) { if evalBool(c) { *ev = evalBool(t) return } *ev = evalBool(f) } func evalBool(e exp[bool]) EvalBool { return *MatchBoolExp(e, new(EvalBool)) }<\/code><\/pre>\n<p><code>Eval<\/code> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f ADT: ExpBoolVars, ExpIntVars, ExpKind. \u041c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0431\u044b\u0442\u044c \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e. \u042d\u0442\u043e \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f.<\/p>\n<pre><code class=\"go\">type Eval struct { EvalInt EvalBool val interface{} }<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>eval<\/code> \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 <code>evalBool<\/code> \u0438 <code>evalInt<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442 <code>exp[t]<\/code>, eval \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 Exp, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0433\u0435\u0442\u0435\u0440\u043e\u0433\u0435\u043d\u043d\u044b\u043c\u0438 \u0441\u043f\u0438\u0441\u043a\u0430\u043c\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439.  \u0412\u043d\u0443\u0442\u0440\u0438 Exp \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0410 <code>exp[t]<\/code> \u043c\u044b \u0432\u0432\u043e\u0434\u0438\u043b\u0438 \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438.<\/p>\n<pre><code class=\"go\">func eval(e Exp) interface{} { var ev Eval  \/\/ \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u044b \u0437\u043d\u0430\u0435\u043c \u0447\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f     \/\/ \u041d\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u043c \u043a\u0430\u043a\u043e\u0439 \u0438\u043c\u0435\u043d\u043d\u043e ek := e.MatchExp(&amp;ev.EvalBool, &amp;ev.EvalInt)  \/\/ \u0410 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u0443\u0437\u043d\u0430\u0435\u043c \u0438 \u0432\u0435\u0440\u043d\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 ek.MatchKind(&amp;ev) return ev.val } func (ev *Eval) Bool(ExpBoolVars) { ev.val = ev.EvalBool } func (ev *Eval) Int(ExpIntVars) { ev.val = ev.EvalInt }<\/code><\/pre>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0423 \u0432\u0441\u0435\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u043e\u0434\u0442\u0438\u043f <code>exp[t]<\/code>. \u041a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0438\u043f\u043e\u0432.<\/p>\n<pre><code class=\"go\">var e00 = Lit(false) var e01 = Lit(42) var e02 = Add(e01, Lit(22)) var e03 = Or(e00, Lit(true)) var e04 = Lt(e02, e01) var e05 = If[int](e04, e01, e02) var e06 = If[bool](e03, e03, e00)<\/code><\/pre>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432 \u0433\u0435\u0442\u0435\u0440\u043e\u0433\u0435\u043d\u043d\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0435:<\/p>\n<pre><code class=\"go\">var progs = []Exp{ e01, e02, e03, e04, If[int](e04, e01, e02), If[bool](e03, e03, e00), }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f (\u043d\u0435 \u0437\u043d\u0430\u044f \u0435\u0433\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0442\u0438\u043f) \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0443 <code>eval<\/code> <\/p>\n<pre><code class=\"go\">func main() { for _, p := range progs { fmt.Printf(\"%v=%v\\n\", eval(p), p) } }<\/code><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<pre><code class=\"go\">42=(lit 42) 64=(add (lit 42) (lit 22)) true=(or (lit false) (lit true)) false=(lt (add (lit 42) (lit 22)) (lit 42)) 64=(if (lt (add (lit 42) (lit 22)) (lit 42)) (lit 42) (add (lit 42) (lit 22))) true=(if (or (lit false) (lit true)) (or (lit false) (lit true)) (lit false))<\/code><\/pre>\n<h2>\u0421\u0441\u044b\u043b\u043a\u0438<\/h2>\n<p><a class=\"anchor\" name=\"sources\" id=\"sources\"><\/a><\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/okmij.org\/ftp\/tagless-final\/course\/Boehm-Berarducci.html\" rel=\"noopener noreferrer nofollow\">Beyond Church encoding: Boehm-Berarducci isomorphism<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/fprog.ru\/2010\/issue4\/roman-dushkin-existentials\/\" rel=\"noopener noreferrer nofollow\">\u0420\u043e\u043c\u0430\u043d \u0414\u0443\u0448\u043a\u0438\u043d. \u041c\u043e\u043d\u043e\u043c\u043e\u0440\u0444\u0438\u0437\u043c, \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u0438\u0437\u043c \u0438\u00a0\u044d\u043a\u0437\u0438\u0441\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b<\/a><\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/838268\/\"> https:\/\/habr.com\/ru\/articles\/838268\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e, \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 DSL \u043d\u0430 Go. \u0420\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c, \u0442.\u0435. \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0441\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f (\u0442\u0435\u0440\u043c\u044b), \u043d\u043e \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u0442\u0438\u043f\u043e\u0432 DSL \u043e\u0434\u0438\u043d-\u043a-\u043e\u0434\u043d\u043e\u043c\u0443 \u043c\u0430\u043f\u043f\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0442\u0438\u043f\u043e\u0432 Go, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0435\u0441\u044c type-checking \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u043e\u043c.<\/p>\n<p>\u041e\u0431\u044b\u0447\u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f <abbr class=\"habraabbr\" title=\"\u041e\u0431\u043e\u0431\u0449\u0435\u043d\u043d\u044b\u0435 \u0430\u043b\u0433\u0435\u0431\u0440\u0430\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445\" data-title=\"&lt;p&gt;\u041e\u0431\u043e\u0431\u0449\u0435\u043d\u043d\u044b\u0435 \u0430\u043b\u0433\u0435\u0431\u0440\u0430\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445&lt;\/p&gt;&lt;p&gt;&lt;\/p&gt;\" data-abbr=\"GADT\">\u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b&lt;\/p&gt;&lt;p&gt;&lt;\/p&gt;&#187; data-abbr=&#187;GADT&#187;>GADT<\/abbr> \u0438\u043b\u0438 <abbr class=\"habraabbr\" title=\"Higher-kinded types - \u0442\u0438\u043f\u044b \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430\" data-title=\"&lt;p&gt;Higher-kinded types - \u0442\u0438\u043f\u044b \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430&lt;\/p&gt;&lt;p&gt;&lt;\/p&gt;\" data-abbr=\"HKT\">lt;p&gt;&lt;\/p&gt;&#187; data-abbr=&#187;HKT&#187;>HKT<\/abbr>. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043d\u0438 \u043e\u0442 \u043f\u0435\u0440\u0432\u043e\u0433\u043e, \u043d\u0438 \u043e\u0442 \u0432\u0442\u043e\u0440\u043e\u0433\u043e.<\/p>\n<p>\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Universal_quantification\" rel=\"noopener noreferrer nofollow\">\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e<\/a> \u043a\u0432\u0430\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Boehm-Berarducci <a href=\"#sources\" rel=\"noopener noreferrer nofollow\">[1]<\/a> \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <a href=\"https:\/\/en.wikipedia.org\/wiki\/Existential_quantification\" rel=\"noopener noreferrer nofollow\">\u044d\u043a\u0437\u0438\u0441\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0435<\/a> \u043a\u0432\u0430\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 (\u0431\u0435\u0437 \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u0438 \u0432 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u0438\u0437\u043c\u0435 \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u0437\u0430 \u0441\u0447\u0435\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u044d\u043a\u0437\u0438\u0441\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0442\u0438\u043f\u0430\u043c\u0438).<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041f\u0440\u043e \u044d\u043a\u0437\u0438\u0441\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0441\u043c. <a href=\"https:\/\/sources\" rel=\"noopener noreferrer nofollow\">[2]<\/a><\/p>\n<\/div>\n<\/details>\n<p>\u041a\u0430\u043a \u0438 \u0430\u043b\u0433\u0435\u0431\u0440\u0430\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043a\u0440\u044b\u0442\u043e (\u043d\u0435\u043b\u044c\u0437\u044f \u0431\u0435\u0437 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043e\u0434\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 statement), \u043d\u043e \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d-\u043c\u0430\u0442\u0447\u0438\u043d\u0433\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u043f\u043e\u043b\u043d\u043e\u0442\u0443 \u0432 compile-time. \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0435 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 GADT \u0432 \u0441\u0442\u0438\u043b\u0435 Tagless-final \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u0435 \u0442\u0435\u0440\u043c\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 Go \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438, \u043d\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0435 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u044e\u0442\u0441\u044f. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u043a\u0440\u044b\u0442\u043e\u0441\u0442\u044c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440 \u0432 \u043f\u043e\u043b\u044c\u0437\u0443 \u0431\u043e\u043b\u044c\u0448\u0435\u0439 type-safety, \u043d\u043e \u043f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0448\u0438\u0442\u044c <a href=\"https:\/\/en.wikipedia.org\/wiki\/Expression_problem\" rel=\"noopener noreferrer nofollow\">expression problem<\/a>.<\/p>\n<p>\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 GADT (\u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430 Haskell):<\/p>\n<pre><code class=\"haskell\">data Exp a where     Lit :: a -&gt; Exp a     Add :: Exp Int -&gt; Exp Int -&gt; Exp Int     Or  :: Exp Bool -&gt; Exp Bool -&gt; Exp Bool     Lt  :: Exp Int -&gt; Exp Int -&gt; Exp Bool     If  :: Exp Bool -&gt; Exp a -&gt; Exp a -&gt; Exp a<\/code><\/pre>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f DSL<\/h2>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 Exp \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u043d\u0430\u0448\u0435\u043c eDSL. \u041c\u0435\u0442\u043e\u0434 MatchExp \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0435\u0442 ADT \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. ExpBoolVars \u0438 ExpIntVars \u044d\u0442\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0439 (<a href=\"https:\/\/en.wikipedia.org\/wiki\/Continuation\" rel=\"noopener noreferrer nofollow\">continuations<\/a>). \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f ExpKind \u0441\u0442\u0440\u043e\u0433\u043e \u0433\u043e\u0432\u043e\u0440\u044f \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u0435\u043d \u0434\u043b\u044f \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u0442\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u0435\u0439 \u0441\u043e\u043e\u0431\u0449\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0435 \u0438\u0437 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0439 \u0431\u044b\u043b\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<pre><code class=\"go\">type Exp interface { MatchExp(ExpBoolVars, ExpIntVars) ExpKind }<\/code><\/pre>\n<p>\u0412\u0432\u0435\u0434\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043e\u0441\u0442\u044b\u043b\u044c, \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 <code>ety<\/code> \u0434\u043b\u044f \u0434\u0435\u043d\u043e\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u0438 DSL<\/p>\n<pre><code class=\"go\">type ety interface { bool | int }<\/code><\/pre>\n<p><code>exp[t]<\/code> &#8212; \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f DSL-\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 t, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u0430\u043f\u043f\u0438\u0442\u0441\u044f \u043d\u0430 Go-\u0442\u0438\u043f t. \u041d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u044b\u043c \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 Exp. \u041f\u0440\u0438\u0447\u0438\u043d\u0430 \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u044c Exp, \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c \u0447\u0442\u043e t \u044d\u0442\u043e \u0444\u0430\u043d\u0442\u043e\u043c\u043d\u044b\u0439 \u0442\u0438\u043f (\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 compile-time \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0438\u043f\u043e\u0432). \u041a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0435\u0441\u0442\u0435\u0433\u043e\u0432\u043e\u0435 (tagless), \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0437\u0430 \u044d\u043a\u0437\u0438\u0441\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u043e\u043c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u0435\u0442\u0435\u0440\u043e\u0433\u0435\u043d\u043d\u044b\u0435 \u0441\u043f\u0438\u0441\u043a\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439.<\/p>\n<pre><code class=\"go\">type exp[t ety] interface { Exp }<\/code><\/pre>\n<p><code>ExpBoolVars, ExpIntVars<\/code> \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0446\u0438\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u0432 ADT. \u0427\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u0442\u0438\u043f\u043e\u0432 \u0443 DSL \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c. \u0417\u0434\u0435\u0441\u044c \u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e, \u043d\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u0432\u0441\u0435 \u0435\u0449\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0438\u043c\u043e\u0440\u0444\u043d\u044b\u043c\u0438.<\/p>\n<pre><code class=\"go\">\/\/ \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0431\u0443\u043b\u0435\u0432\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 type ExpBoolVars interface { Lit(bool) Or(exp[bool], exp[bool]) Lt(exp[int], exp[int]) If(exp[bool], exp[bool], exp[bool]) }  \/\/ \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f int \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 type ExpIntVars interface { Lit(int) Add(exp[int], exp[int]) If(exp[bool], exp[int], exp[int]) }<\/code><\/pre>\n<p><code>ExpKind<\/code> \u0435\u0449\u0435 \u043e\u0434\u0438\u043d ADT \u043d\u0443\u0436\u043d\u044b\u0439 \u0447\u0442\u043e\u0431\u044b \u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u0438\u0445 \u0442\u0438\u043f\u0430\u043c. <code>KindVars<\/code> &#8212; \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"go\">type ExpKind interface { MatchKind(KindVars) }  type KindVars interface { Bool(ExpBoolVars) Int(ExpIntVars) }<\/code><\/pre>\n<p><code>boolVal, intVal<\/code> \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 ExpKind.<\/p>\n<pre><code class=\"go\">type boolVal struct{ ev ExpBoolVars } type intVal struct{ ev ExpIntVars }  func (b boolVal) MatchKind(v KindVars) { v.Bool(b.ev) } func (n intVal) MatchKind(v KindVars)  { v.Int(n.ev) }<\/code><\/pre>\n<p><code>MatchIntExp, MatchBoolExp<\/code> &#8212; \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u0442\u0435\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443\u0436\u0435 \u0437\u043d\u0430\u0435\u043c \u0438\u0445 \u0442\u0438\u043f.<\/p>\n<pre><code class=\"go\">func MatchIntExp[tv ExpIntVars](e exp[int], v tv) tv { e.MatchExp(nil, v) return v }  func MatchBoolExp[tv ExpBoolVars](e exp[bool], v tv) tv { e.MatchExp(v, nil) return v }<\/code><\/pre>\n<p><code>lit[t], add, or, lt, if_<\/code> \u043a\u043e\u0434\u0438\u0440\u0443\u044e\u0442 \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0415\u0441\u043b\u0438 ADT \u044d\u0442\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435, \u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u0443\u0442\u043e\u0447\u043d\u044f\u0435\u043c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439.<\/p>\n<pre><code class=\"go\">type lit[t ety] struct{ val t } type add struct{ a, b exp[int] } type or struct{ a, b exp[bool] } type lt struct{ a, b exp[int] } type if_[t ety] struct { c exp[bool] t exp[t] f exp[t] }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b <code>MatchExp<\/code> \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442 <code>exp[t]<\/code>. \u041a\u0430\u0436\u0434\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f, \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0438\u0445. \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c switch \u043f\u043e \u0442\u0438\u043f\u0430\u043c \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043e\u0439\u0442\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f Go \u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u0432\u0430\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 Go \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u044c \u0447\u0442\u043e \u043d\u0430\u0431\u043e\u0440 case \u0432\u0435\u0442\u043e\u043a \u043f\u043e\u043b\u043e\u043d (exhaustive) \u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u044c default. \u041d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f DSL \u043d\u0438\u043a\u0430\u043a\u0438\u0445 switch \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f.<\/p>\n<pre><code class=\"go\">func (l lit[t]) MatchExp(bv ExpBoolVars, nv ExpIntVars) ExpKind { switch v := interface{}(l).(type) { case lit[bool]: bv.Lit(bool(v.val)) return boolVal{bv} case lit[int]: nv.Lit(int(v.val)) return intVal{nv} default: panic(\"unreachable\") } } func (n add) MatchExp(_ ExpBoolVars, v ExpIntVars) ExpKind { v.Add(n.a, n.b) return intVal{v} } func (b or) MatchExp(v ExpBoolVars, _ ExpIntVars) ExpKind { v.Or(b.a, b.b) return boolVal{v} } func (b lt) MatchExp(v ExpBoolVars, _ ExpIntVars) ExpKind { v.Lt(b.a, b.b) return boolVal{v} } func (e if_[t]) MatchExp(bv ExpBoolVars, nv ExpIntVars) ExpKind { switch interface{}(*new(t)).(type) { case bool: bv.If(e.c, e.t.(exp[bool]), e.f.(exp[bool])) return boolVal{bv} case int: nv.If(e.c, e.t.(exp[int]), e.f.(exp[int])) return intVal{nv} default: panic(\"unreachable\") } }<\/code><\/pre>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c <code>fmt.Stringer<\/code> \u0434\u043b\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439.<\/p>\n<pre><code class=\"go\">func (l lit[t]) String() string { return fmt.Sprintf(\"(lit %v)\", l.val) } func (n add) String() string    { return fmt.Sprintf(\"(add %v %v)\", n.a, n.b) } func (b or) String() string     { return fmt.Sprintf(\"(or %v %v)\", b.a, b.b) } func (b lt) String() string     { return fmt.Sprintf(\"(lt %v %v)\", b.a, b.b) } func (e if_[t]) String() string { return fmt.Sprintf(\"(if %v %v %v)\", e.c, e.t, e.f) }<\/code><\/pre>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043a\u0430\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0434\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0442\u0438\u043f\u044b \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u044b\u0432\u043e\u0434 \u0442\u0438\u043f\u043e\u0432 \u0432 Go \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043b\u0443\u0447\u0448\u0435 \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u044d\u0442\u043e \u0432\u0441\u0435 \u0435\u0449\u0435 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u043b\u044f <code>If<\/code>, \u0447\u0442\u043e \u0443\u0434\u0440\u0443\u0447\u0430\u0435\u0442. \u0415\u0441\u043b\u0438 \u0431\u044b Go \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0432\u044b\u0432\u043e\u0434 \u0442\u0438\u043f\u043e\u0432 \u043f\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0443 \u0425\u0438\u043d\u0434\u043b\u0438 &#8212; \u041c\u0438\u043b\u043d\u0435\u0440\u0430, \u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0431\u044b \u043d\u0435 \u0431\u044b\u043b\u043e.<\/p>\n<pre><code class=\"go\">func Lit[t ety](v t) lit[t] { return lit[t]{v} } func Add(a, b exp[int]) add { return add{a, b} } func Or(a, b exp[bool]) or  { return or{a, b} } func Lt(a, b exp[int]) lt   { return lt{a, b} } func If[t ety](c exp[bool], tr, fl exp[t]) if_[t] { return if_[t]{c, tr, fl} }<\/code><\/pre>\n<h2>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 DSL<\/h2>\n<p>\u0412\u0441\u0435 \u0447\u0442\u043e \u0431\u044b\u043b\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043e \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0431\u044b\u043b\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439. \u0414\u0430\u043b\u0435\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f DSL. \u041c\u044b \u0445\u043e\u0442\u0438\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u044e ADT \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u0430 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0448\u0430\u0433\u0430 (<a href=\"https:\/\/en.wikipedia.org\/wiki\/Operational_semantics#Big-step_semantics\" rel=\"noopener noreferrer nofollow\">big-step<\/a>). \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u0438 &#8212; \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043d\u0435 \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440. \u041a\u0430\u043a \u043f\u0440\u0438\u043c\u0435\u0440 \u043c\u044b \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u044e \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442 \u0432 native \u043a\u043e\u0434.<\/p>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u044e eval.<\/p>\n<p><code>EvalInt<\/code> \u044d\u0442\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0432\u0437\u0430\u0438\u043c\u043d\u043e \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0442\u0438\u043f\u0430 int. <code>EvalInt<\/code> \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 <code>ExpIntVars<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0432\u0441\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f (\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u043f\u0430\u0442\u0442\u0435\u0440\u043d-\u043c\u0430\u0442\u0447\u0438\u043d\u0433\u0430), \u0430 \u0438\u043d\u0430\u0447\u0435 \u043a\u043e\u0434 \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f. \u041f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c <code>EvalBool<\/code>.<\/p>\n<pre><code class=\"go\">type EvalInt int type EvalBool bool  func (ev *EvalInt) Lit(n int) { *ev = EvalInt(n) } func (ev *EvalInt) Add(a, b exp[int]) { *ev = evalInt(a) + evalInt(b) } func (ev *EvalInt) If(c exp[bool], t, f exp[int]) { if evalBool(c) { *ev = evalInt(t) return } *ev = evalInt(f) }  func evalInt(e exp[int]) EvalInt { \/\/ \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0437\u043d\u0430\u0435\u0442, \u0447\u0442\u043e \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 exp[int], \/\/ \u0442\u0430\u043a \u0447\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u044b\u0437\u0432\u0430\u0442\u044c MatchBoolExp \u043f\u043e \u043e\u0448\u0438\u0431\u043a\u0435. return *MatchIntExp(e, new(EvalInt)) }  func (ev *EvalBool) Lit(b bool) { *ev = EvalBool(b) } func (ev *EvalBool) Or(a, b exp[bool]) { *ev = evalBool(a) || evalBool(b) } func (ev *EvalBool) Lt(a, b exp[int]) { if evalInt(a) &lt; evalInt(b) { *ev = EvalBool(true) return } *ev = EvalBool(false) } func (ev *EvalBool) If(c, t, f exp[bool]) { if evalBool(c) { *ev = evalBool(t) return } *ev = evalBool(f) } func evalBool(e exp[bool]) EvalBool { return *MatchBoolExp(e, new(EvalBool)) }<\/code><\/pre>\n<p><code>Eval<\/code> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f ADT: ExpBoolVars, ExpIntVars, ExpKind. \u041c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0431\u044b\u0442\u044c \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e. \u042d\u0442\u043e \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f.<\/p>\n<pre><code class=\"go\">type Eval struct { EvalInt EvalBool val interface{} }<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>eval<\/code> \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 <code>evalBool<\/code> \u0438 <code>evalInt<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442 <code>exp[t]<\/code>, eval \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 Exp, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0433\u0435\u0442\u0435\u0440\u043e\u0433\u0435\u043d\u043d\u044b\u043c\u0438 \u0441\u043f\u0438\u0441\u043a\u0430\u043c\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439.  \u0412\u043d\u0443\u0442\u0440\u0438 Exp \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0410 <code>exp[t]<\/code> \u043c\u044b \u0432\u0432\u043e\u0434\u0438\u043b\u0438 \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438.<\/p>\n<pre><code class=\"go\">func eval(e Exp) interface{} { var ev Eval  \/\/ \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u044b \u0437\u043d\u0430\u0435\u043c \u0447\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f     \/\/ \u041d\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u043c \u043a\u0430\u043a\u043e\u0439 \u0438\u043c\u0435\u043d\u043d\u043e ek := e.MatchExp(&amp;ev.EvalBool, &amp;ev.EvalInt)  \/\/ \u0410 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u0443\u0437\u043d\u0430\u0435\u043c \u0438 \u0432\u0435\u0440\u043d\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 ek.MatchKind(&amp;ev) return ev.val } func (ev *Eval) Bool(ExpBoolVars) { ev.val = ev.EvalBool } func (ev *Eval) Int(ExpIntVars) { ev.val = ev.EvalInt }<\/code><\/pre>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0423 \u0432\u0441\u0435\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u043e\u0434\u0442\u0438\u043f <code>exp[t]<\/code>. \u041a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0438\u043f\u043e\u0432.<\/p>\n<pre><code class=\"go\">var e00 = Lit(false) var e01 = Lit(42) var e02 = Add(e01, Lit(22)) var e03 = Or(e00, Lit(true)) var e04 = Lt(e02, e01) var e05 = If[int](e04, e01, e02) var e06 = If[bool](e03, e03, e00)<\/code><\/pre>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432 \u0433\u0435\u0442\u0435\u0440\u043e\u0433\u0435\u043d\u043d\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0435:<\/p>\n<pre><code class=\"go\">var progs = []Exp{ e01, e02, e03, e04, If[int](e04, e01, e02), If[bool](e03, e03, e00), }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f (\u043d\u0435 \u0437\u043d\u0430\u044f \u0435\u0433\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0442\u0438\u043f) \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0443 <code>eval<\/code> <\/p>\n<pre><code class=\"go\">func main() { for _, p := range progs { fmt.Printf(\"%v=%v\\n\", eval(p), p) } }<\/code><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<pre><code class=\"go\">42=(lit 42) 64=(add (lit 42) (lit 22)) true=(or (lit false) (lit true)) false=(lt (add (lit 42) (lit 22)) (lit 42)) 64=(if (lt (add (lit 42) (lit 22)) (lit 42)) (lit 42) (add (lit 42) (lit 22))) true=(if (or (lit false) (lit true)) (or (lit false) (lit true)) (lit false))<\/code><\/pre>\n<h2>\u0421\u0441\u044b\u043b\u043a\u0438<\/h2>\n<p><a class=\"anchor\" name=\"sources\" id=\"sources\"><\/a><\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/okmij.org\/ftp\/tagless-final\/course\/Boehm-Berarducci.html\" rel=\"noopener noreferrer nofollow\">Bey<\/a><\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-430182","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/430182","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=430182"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/430182\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=430182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=430182"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=430182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}