SchemeとActor理論

「最初のSchemeインタプリタは関数とアクターの双方を実装していた」

http://www.ice.nuie.nagoya-u.ac.jp/~h003149b/lang/p/frag/frag_f.html

例えば「1と2と3からなるメッセージをアクターaに送る」という事を [a 1 2 3]と書く
新しくアクターを作る事もできる。そのためにはalpha構文を使う。例えば (alpha (u k) [+ u u k])

  (define _fact
    (alpha (n k)
      (if (= n 0)
          [k 1]
          [_fact (- n 1)
                 (alpha (u)        ; c
                   [k (* n u)])])))
http://www.ice.nuie.nagoya-u.ac.jp/~h003149b/lang/actor/actor.html

これにならって、階乗をErlang,Scala,IoのActorで書いてみる。

Erlang

alpha構文には、spawn(fun()->receive ... end end)が対応する。

-module(fact).
-compile(export_all).

fact() -> spawn(fun()->receive
  {0,K} -> K ! 1;
  {N,K} -> fact() ! {N-1,spawn(fun()->receive R -> K ! (N*R) end end)}
end end).

main(_) -> fact() ! {4,spawn(fun()->receive R -> io:format("~p~n",[R]) end end)}.

Scala

alpha構文には、actor{receive{case ... }}が対応する。

import scala.actors._
import scala.actors.Actor._

def fact():Actor = actor{receive{
  case (0    ,k:Actor) => k ! 1
  case (n:Int,k:Actor) => fact() ! (n-1,actor{receive{case r:Int => k ! (n*r)}})
}}

fact() ! (4,actor{receive{case r => println(r)}})

Io版

Ioはもともとメッセージセンドのパラダイムで作られているので、@@はそのメッセージセンドを非同期化するもの、という位置づけ。
関係ないけど、Ioでもパターンマッチが使いたい。

fact := block(n,k,
  if(n==0,k @@ call(1),
       fact @@ call(n-1,block(r,k @@ call(n*r)))))

fact @@ call(4,block(r,r println))
while(yield,nil)

Gauche

util.matchをつかってErlang版やScala版に似せて書いたバージョン。

(use util.match)
(define-macro (alpha . body) `(match-lambda* ,@body))

(define fact (alpha
  ((0 k) [k 1])
  ((n k) [fact (- n 1) (alpha ((r) [k (* n r)]))])
))

[fact 4 print]