2017年07月14日

numb-lambdaでhello, world

それでは、numb-lambda言語を使って有名なhello, worldプログラムを作りましょう。

まず、numb-lambdaを起動します。
$ numb-lambda


行頭の>はプロンプトです。その後ろにカーソルが点滅しています。これで、numb-lambdaインタープリタのREPL(Read Evaluate Print Loop)が開始されます。

ここで、次のように入力してください。
> "hello, world"
"hello, world"


"hello, world"がエコーされた筈です。ひじょうに簡単ですが詐欺のようですね。それにダブルクォートで囲まれていて、一般的なhello, worldプログラムとは異ります。numb-lambdaは、"hello, world"という文字列リテラルを読んで(Read)、評価し(Evaluate)、印字して(Print)、次のプロンプトを表示しました。(Loop)
一般的なLISPはリテラルを評価するとリテラルそのものが得られます。

もう少しまともに書いてみましょう。
> (display "hello, world")
hello, world>

ダブルクォートが取れて少しマトモになりました。しかし、改行がされていないため、次のプロンプトがhello, worldの直後に表示されています。
> (begin
    (display "hello, world")
    (newline))
hello, world


はい、今度は期待どおりになったと思います。beginを使うと複数の文を逐次実行させることができます。このように、LISPでは通常、括弧内の最初の要素がオペレータとなり処理を行います。

displaynewlineは、共に印字とい副作用を期待されたオペレータです。

今度は関数を使ってみましょう。
> ((lambda ()
    (display "hello, world")
    (newline)))
hello, world


難しいですか?ここでは、(lambda () (display "hello, world")(newline))が関数です。それが外側の括弧の最初の要素であるのでオペレータとして動作します。ですから、この行は関数を呼び出しているのです。lambdaの括弧の後ろは逐次実行されます。beginは必要ありません)あれ、でも、ちょっと待ってください。これでは関数が再利用できないではありませんか。そのとおり。再利用するには関数を変数にバインドする必要があります。次のようにします。
> (define say-hello
    (lambda ()
      (display "hello, world")
      (newline)))
>

これで、関数がsay-helloという変数にバインドされました。これを呼び出すには次のようにします。
> (say-hello)
hello, world
>


関数に引数を与えることができるよう、少し変更します。

> (define say-hello-revised
    (lambda (s)
      (display "hello, ")
      (display s)
      (newline)))
> (say-hello-revised "namb")
hello, namb
>

"namb"を様々に変更して再実行してみてください。

最後に関数を定義するために構文糖(シンタックスシュガー)が利用できることを示して終りとします。

> (define (say-hello-revised^2 s)
    (display "hello, ")
    (display s)
    (newline))
> (say-hello-revised^2 "foo bar")
hello, foo bar
>

今回は以上です。いかがですが、難しくはなかったでしょう。