Diff
Not logged in

Differences From Artifact [388d91fa67a7c403]:

To Artifact [33d07971634f6989]:


350 <pre> 350 <pre> 351 &gt;&gt; @hoge( 1 + 2 ) 351 &gt;&gt; @hoge( 1 + 2 ) 352 polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\eval.d(466 352 polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\eval.d(466 353 [<REPL>:3:7] only @value layer can call native function: + 353 [<REPL>:3:7] only @value layer can call native function: + 354 [<REPL>:3:7] + 354 [<REPL>:3:7] + 355 </pre> 355 </pre> 356 <p> 356 <p> 357 まだエラーですね。これは 実は、リフト関数は | 357 まだエラーですね。これは要するに "+" の意味がわからない、と言っています。 > 358 $(RED $(B レイヤ指定変数定義式)) で、"+" の意味を教えてあげます。 358 </p> 359 </p> 359 <pre> 360 <pre> 360 &gt;&gt; @hoge "+" = fun(x, y) {x} 361 &gt;&gt; @hoge "+" = fun(x, y) {x} > 362 (function:182eca0:18435e0) > 363 &gt;&gt; @hoge( 3 + 4 ) > 364 6 361 </pre> | 365 </pre> > 366 <p> > 367 できました。 > 368 </p> > 369 <p> > 370 他の組み込み関数の意味も決めてみましょう。この <tt>@hoge</tt> レイヤでは、 > 371 引き算のつもりで書いたコードが、掛け算になってしまうだ! > 372 </p> 362 <pre> | 373 <pre> 363 [Layers :: Overview] < 364 < 365 Polemy's runtime environment has many "layer"s. < 366 Usual execution run in the @value layer. < 367 < 368 >> 1 + 2 < 369 3 < 370 >> @value( 1 + 2 ) < 371 3 < 372 < 373 Here you can see that @LayerName( Expression ) executes the inner Expression i | 374 &gt;&gt; @hoge "-" = fun(x, y) {x * y} 374 the @LayerName layer. Other than @value, one other predefined layer exists: @m | 375 (function:1b4c6a0:1b4fbe0) 375 < > 376 &gt;&gt; @hoge( 5 - 6 ) 376 >> @macro( 1+2 ) | 377 polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\eval.d(469 377 {pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>}, | 378 [<REPL>:3:24] only @value layer can call native function: * 378 is@value:app, | 379 [<REPL>:3:24] * 379 args@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@v | 380 [<REPL>:4:8] - 380 is@value:int, | 381 </pre> 381 data@value:1}, < 382 cdr@value:{ < > 382 <p> > 383 5、の意味は 10 で 6 の意味は 12 なので、10 - 12 と見せかけて掛け算して 120 が返るのだ! 383 car@value:{pos@value:{lineno@value:3, column@value:11, filenam | 384 と思いきや、エラーになってしまいました。なぜでしょう。それは、この "-" の定義、 384 is@value:int, | 385 <code>fun(x, y) {x * y}</code> 自体が、<tt>@hoge</tt> レイヤで実行されるからです。 385 data@value:2}, < 386 cdr@value:{}}}, < > 386 掛け算はまだ定義していません。 > 387 </p> 387 fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:<REPL | 388 <p> 388 is@value:var, < > 389 ここは、「普通の」意味の掛け算を使いたいのです。 389 name@value:+}} | 390 この部分については、<tt>@value</tt> レイヤで計算して欲しい。 390 < > 391 そんなときは、レイヤ指定式を使います。 391 (Sorry, this pretty printing is not available on the actual interpreter...) | 392 </p> 392 This evaluates the expression 1+2 in the @macro layer. In this layer, the mean | 393 <pre> 393 the program is its abstract syntax tree. | 394 &gt;&gt; @hoge "-" = fun(x, y) {$(B @value(@hoge(x) * @hoge(y)))} 394 < > 395 (function:1b086c0:1b4fbe0) 395 You can interleave layers. | 396 &gt;&gt; @hoge( 5 - 6 ) 396 The root node of the abstract syntax tree is function "app"lication. < 397 < 398 >> @value(@macro( 1+2 ).is) < > 397 120 > 398 </pre> > 399 <p> 399 app | 400 できました。掛け算は、<tt>@value</tt> レイヤの意味で実行します。 400 < 401 < 402 < > 401 各変数は、<tt>@hoge</tt> レイヤで計算された意味を使いますという意味になります。 > 402 </p> > 403 )) 403 [Layers :: Defining a new layer] | 404 $(SECTION 関数の自動リフト, $(SECBODY > 405 <p> > 406 続きです。ちょっと関数を定義してみました。 > 407 </p> > 408 <pre> > 409 &gt;&gt; def twoMinus(x,y,z) { x - y - z } > 410 (function:1b26420:1b4fbe0) > 411 &gt;&gt; twoMinus(1,2,3) > 412 -4 > 413 </pre> > 414 <p> > 415 <tt>@value</tt> レイヤで実行すると、当然、1 から 2 と 3 を引て、-4 です。 > 416 </p> > 417 <pre> > 418 &gt;&gt; @hoge( twoMinus(1,2,3) ) > 419 48 > 420 </pre> > 421 <p> > 422 <tt>@hoge</tt> レイヤだと、2 と 4 と 6 を掛け算するので、結果は 48 です。 > 423 </p> > 424 <p> > 425 1, 2, 3 のような値と、+ や - のような組み込み関数について、 > 426 「<tt>@hoge</tt> レイヤでの意味」をレイヤを定義する人が決てやる必要があります。 > 427 でも、それさえ決めれば、あとはプログラム中で自分で定した関数はすべて、 > 428 Polemy 側で自動的にそのレイヤでの意味で実行できるようにります。 > 429 </p> > 430 <p> > 431 レイヤ指定変数定義を使って、変数の意味をそのレイヤでけ上書きして、 > 432 違う意味を与えてやっても構いません。 > 433 </p> > 434 <pre> > 435 &gt;&gt; def twoMinus(x,y,z) { x - y - z } $(D_COMMENT # @value レイヤでの定義) > 436 &gt;&gt; @hoge twoMinus(x,y,z) { 21 } $(D_COMMENT # @hoge レイヤで定義) > 437 &gt;&gt; twoMinus(1,2,3) > 438 -4 > 439 &gt;&gt; @hoge( twoMinus(1,2,3) ) > 440 42 > 441 </pre> > 442 <p> > 443 こんな感じで。 > 444 </p> > 445 )) > 446 $(SECTION レイヤ指定引数, $(SECBODY > 447 <p> > 448 ここまでのサンプルでは、コードを書いた人が、レイヤ指式で明示的にレイヤを切り替えていました。 > 449 $(RED $(B レイヤ指定引数)) を使うと、ライブラリ関数などをくときに、 > 450 「この関数の第2引数は <tt>@hoge</tt> レイヤで計算して欲し」 > 451 といった指定ができます。 > 452 </p> > 453 <pre> > 454 &gt;&gt; def f(x, y $(B @hoge)) { x + @hoge(y) } > 455 &gt;&gt; f(1, 2) 404 | 456 5 405 To define a new layer, you should first tell how to "lift" existing values two < 406 Let us define the "@type" layer, where the meaning of programs is their static < > 457 </pre> > 458 <p> > 459 f の第2引数は、必ず <tt>@hoge</tt> レイヤで解釈されます。 > 460 </p> > 461 <pre> > 462 &gt;&gt; def ff(x, y $(B @hoge @value)) { x + @hoge(y) + @value(y) } > 463 &gt;&gt; ff(1, 2) 407 | 464 7 > 465 </pre> > 466 <p> > 467 <tt>@hoge</tt> と <tt>@value</tt> の両方のレイヤで解釈して欲しい、という欲張りな人は、 > 468 レイヤ指定を複数並べて下さい。 > 469 </p> > 470 <p> > 471 なにもレイヤ指定がないと、$(RED $(B ニュートラルレイヤ指)) と呼ばれ、 > 472 その関数の呼び出し側が解釈されていたレイヤと同じとこにセットされます。 > 473 <tt>let</tt>, <tt>var</tt>, <tt>def</tt> による変数定義も同じで、 > 474 <tt>@hoge x = ...</tt> とレイヤを明示するとそのレイヤでの変数の意味が定義されますが、 > 475 <tt>let x = ...</tt> とレイヤ指定しないで書くと、現在解釈中レイヤに定義、という動作をします。 > 476 </p> > 477 )) > 478 $(SECTION ボトムと自動メモ化, $(SECBODY > 479 <p> > 480 パターンマッチ失敗時と、"..." という式を実行したときと再帰が無限に止まらなくなったとき、 > 481 には、Polemy のコードは実行時エラーで終了します……<tt>@value</tt> レイヤならば。 > 482 </p> > 483 <p> > 484 ユーザー定義レイヤでは、このような時にも実行時エラーならず、 > 485 「$(RED $(B ボトム))」という特別な値がリフト関数に渡されす。 > 486 組み込みの <tt>_isbot</tt> 関数で、ボトムかどうか判定できます。 > 487 </p> > 488 <p> > 489 「再帰が無限に止まらなくなったとき」は、 > 490 ある引数で呼び出された関数が、return するよりも前にまたじ引数で呼び出されたら、 > 491 ループしていると見なすことで判定しています。 > 492 これを判定する実装の副作用として、ユーザー定義のレイでは、関数は全てメモ化されています。 > 493 つまり、ある関数が2回同じ引数同じ環境で呼び出された、1回目の答えをキャッシュしておいて、 > 494 2回目は計算をせずに即座にキャッシュをひいて答えを返ます。 > 495 </p> > 496 )) > 497 $(SECTION まとめ, $(SECBODY > 498 <p> > 499 まとめると、以下の機能があります。 > 500 </p> > 501 <ul> > 502 <li><tt>@@layer = fun(x) { ... } in ...</tt> で、 > 503 <tt>@value</tt> レイヤの値に別のレイヤでの意味を与えるリト関数を定義</li> > 504 <li><tt>@layer x = ... in ...</tt> で、そのレイヤでのその変数の味を定義</li> > 505 <li>どちらも let/var/def 式の特殊形なので、<tt>@@layer(x) { ... } in ...</tt> などの略記も > 506 <li>式の途中で @layer( ... ) と書くと、レイヤを明示的に切り替えられる</li> > 507 <li>関数の仮引数に fun(x @layer){ ... } とレイヤを指定すると > 508 対応する実引数はそのレイヤで解釈される。</li> > 509 </ul> > 510 <p> > 511 </p> > 512 )) > 513 $(SECTION 例, $(SECBODY > 514 <p> > 515 具体的な「値」のかわりに、その「メタ情報」を取り出し、それが処理によってどう変化するか、 > 516 といった情報を解析するのを主な用途として、この機能をってみました。 > 517 プログラムでよく使われる代表的なメタ情報は、「型」で。 > 518 サンプルとしては、sample/type.pmy をご覧下さい。以下、簡単概略。 > 519 </p> > 520 <pre> 408 >> @@type = fun(x) { | 521 @@type = fun(x) { 409 >> if( _isint(x) ) { "int" } else { | 522 if( _isint(x) ) then "int" 410 >> if( _isfun(x) ) { x } else { "unknown" } } < 411 >> } < 412 (Note: polemy REPL may warn some exception here but please ignore) < > 523 else if( _isstr(x) ) then "str" > 524 else if( _isbot(x) ) then "runtime error" > 525 else "type error" 413 | 526 } 414 For simplicity, I here deal only with integers. < 415 _isint is a primitive function of Polemy that checks the dynamic type of a val < 416 For function, leaving it untouched works well for almost all layers. < 417 < > 527 </pre> > 528 <pre> 418 >> @type( 1 ) | 529 &gt;&gt; @type( 1 ) 419 int 530 int 420 >> @type( 2 ) | 531 &gt;&gt; @type( 2 ) 421 int 532 int 422 >> @type( "foo" ) | 533 &gt;&gt; @type( "foo" ) 423 unknown < 424 < > 534 str > 535 </pre> 425 Fine! Let's try to type 1+2. | 536 <p> 426 < > 537 こんな風に、値をメタ情報へ抽象化するのが、リフト関数す。 427 >> @type( 1 + 2 ) | 538 </p> 428 ...\value.d(119): [<REPL>:6:8] only @value layer can call native function | 539 <p> 429 < > 540 型に抽象化したレイヤでの、組み込み関数の意味を考えまょう。 430 Note that the behavior of this program is | 541 "+" は、"int" と "int" を足したら "int" を返す関数です。 431 - run 1+2 in the @type layer < 432 and NOT < > 542 それ以外なら"型エラー"を返します。そういう関数です。 > 543 </p> 433 - run 1+2 in @value and obtain 3 and run 3 in the @type. | 544 <pre> 434 The problem is, the variable "+" is defined only in the @value layer. | 545 var int_int_int = fun (x, y) {@value( 435 To carry out computation in the @type layer. We need to define it also | 546 var tx = @type(x); 436 in the @type layer. | 547 var ty = @type(y); > 548 if tx=="runtime error" then ty > 549 else if ty=="runtime error" then tx > 550 else if tx=="int" && ty=="int" then "int" > 551 else "type error" > 552 )}; 437 553 438 To define some variable in a specific layer, use @LayerName in place of < 439 (let|var|def)s. < 440 < 441 >> let x = 2 < 442 >> @value x = 2 < 443 >> @type x = "int" < 444 >> @hoge x = "fuga" < 445 < 446 For "+", do it like this. < 447 < 448 >> @type "+" = fun(x,y) {@value( | 554 @type "+" = int_int_int; 449 >> if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" } < 450 >> )} < 451 polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24 < 452 < 453 It is just computing the return type from the input type. < 454 Not here that the intended "meaning" of if-then-else is the runtime-branching, < 455 and the meaning of "==" is the value-comparison. These are the @value layer < 456 behavior. So we have defined the function body inside @value layer. < 457 But when we refer the variables x and y, we need its @type layer meaning. < 458 Hence we use @type() there. < 459 < 460 Now we get it. < 461 < > 555 @type "-" = int_int_int; > 556 @type "<" = int_int_int; > 557 </pre> > 558 <pre> 462 >> @type( 1 + 2 ) | 559 &gt;&gt; @type( 1 + 2 ) 463 int 560 int 464 < > 561 &gt;&gt; @type( 1 + "foo" ) 465 Well, but do we have to define the @type layer meaning for every variables??? | 562 type error 466 No. After you defined @type "+", you'll automatically get the following: | 563 </pre> 467 < 468 >> def double(x) { x + x } < > 564 <p> > 565 「実行時エラーについては、それが起きなければ返すはず型」を計算するという定義に、 469 (function:17e4740:1789720) | 566 ここではしています。さらに(ちょっと手抜きで int 以外を考えていない)if の型定義を考えると、 470 < > 567 こんな雰囲気。 471 >> @type( double(123) ) | 568 </p> > 569 <pre> > 570 @type "if" (c, t, e) {@value( > 571 if( @type(c)=="int" || @type(c)=="runtime error" ) then > 572 @type( int_int_int(t(), e()) ) > 573 else > 574 "type error" > 575 )} > 576 </pre> > 577 <p> > 578 関数が自動リフトされるので、フィボナッチ関数の型を調ることができます。 > 579 </p> > 580 <pre> > 581 &gt;&gt; def fib(x) { if x<2 then 1 else fib(x-1)+fib(x-2) }; > 582 &gt;&gt; @type( fib(100000000000000) ) 472 int | 583 int 473 < 474 Every user-defined functions are automatically "lift"ed to the appropriate lay < 475 Only primitive functions like "+" requires @yourNewLayer annotation. < 476 < 477 < 478 < 479 [Layers :: neutral-layer] < 480 < 481 let|var|def is to define a variable in the "current" layer. < 482 Not necessary to the @value layer. < 483 < 484 >> @value( let x = 1 in @value(x) ) < 485 1 < 486 < 487 >> @macro( let x = 1 in @value(x) ) | 584 &gt;&gt; def gib(x) { if x<2 then 1 else gib(x-1)+gib(x-"str") }; 488 polemy.failure.RuntimeException: [<REPL>:14:29] variable x not found | 585 &gt;&gt; @type( gib(100000000000000) ) 489 < > 586 type error 490 >> @macro( let x = 1 in @macro(x) ) | 587 </pre> 491 {pos@value:{lineno@value:15, ... | 588 <p> 492 < 493 < 494 < 495 [Layers :: Layered-Parameters] < 496 < > 589 この定義で <tt>fib(100000000000000)</tt> を <tt>@value</tt> レイヤで通に計算して、 > 590 結果の型を見る、というのでは時間がいくらあっても足りせん。 > 591 いったん <tt>@type</tt> のメタ情報の世界に移ってから計算でるのが、レイヤ機能の肝です。 > 592 </p> > 593 <p> 497 >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} } | 594 正確には、この定義で <tt>@type</tt> レイヤに移ると fib("int") を無限に呼び出し続けて止まらなくなるのですが、 498 (function:1730360:1789720) < 499 < > 595 そこは、自動メモ化による再帰検出でボトム値を返す機能よって、うまく止まっています。 > 596 </p> 500 If you annotate function parameters by @LayerNames, when you invoke the functi | 597 <p> 501 < 502 >> foo(1+2) < > 598 それでも上手く型計算ができない(あるいはすごく遅くな)ような複雑な関数があるかもしれません。 > 599 仕方がないので、型情報をアノテーションとしてつけてあることも可能です。 503 {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REP | 600 </p> 504 is@value:app, arg@value:{... | 601 <pre> 505 /fst@value:3 | 602 @type f = int_int_int; 506 /} | 603 def f(x,y) { ...とても型を計算できないくらい複雑な定義... }; 507 < 508 its corresponding arguments are evaluated in the layer and passed to it. < 509 If you specify multiple layers, the argument expression is run multiple times. < 510 If you do not specify any layer for a parameter, it works in the neutral layer < 511 </pre> 604 </pre> > 605 <p> > 606 これが、レイヤ指定変数定義の典型的な使い道です。 > 607 </p> 512 )) 608 )) 513 ) 609 ) 514 )) 610 )) 515 611 516 612 517 $(SECTION Macro Layers, $(SECBODY 613 $(SECTION Macro Layers, $(SECBODY 518 <p> 614 <p> 519 Polemy 言語組み込みのレイヤは <code>@value</code> と <code>@macro</code> の二つです。 615 Polemy 言語組み込みのレイヤは <code>@value</code> と <code>@macro</code> の二つです。 520 (内部的にはもういくつかありますが、ユーザから直接は使えません。) 616 (内部的にはもういくつかありますが、ユーザから直接は使えません。) 521 <code>@value</code> は、「普通に」普通のセマンティクスでプログラムを実行するレイヤでした。 617 <code>@value</code> は、「普通に」普通のセマンティクスでプログラムを実行するレイヤでした。 522 <code>@macro</code> は、実は、<code>@value</code> よりも前に実行されるレイヤで、 618 <code>@macro</code> は、実は、<code>@value</code> よりも前に実行されるレイヤで、 523 「プログラムを実行するとその構文木を返す」というセマンティクスで動きます。 619 「プログラムを実行するとその構文木を返す」というセマンティクスで動きます。 524 </p> 620 </p> 525 <pre> < 526 (ここに例) < 527 </pre> < 528 <p> 621 <p> 529 動きとしてはこうです。 622 動きとしてはこうです。 530 </p> 623 </p> 531 <ol> 624 <ol> 532 <li>関数呼び出し時(とトップレベル環境の実行開始時)に、 625 <li>関数呼び出し時(とトップレベル環境の実行開始時)に、 533 まず、<code>@macro</code> レイヤでコードを実行。</li> 626 まず、<code>@macro</code> レイヤでコードを実行。</li> 534 <li>返ってきた構文木を、その関数を呼び出したときのレイヤで実行。</li> 627 <li>返ってきた構文木を、その関数を呼び出したときのレイヤで実行。</li>