第6回 Scheme 入門(5月22日)

今日の課題

■ 関数型言語 scheme

scheme は関数型言語 lisp の方言の一つである。

関数型言語では、「<式>を<評価>して,<返り値>を得る」という計算を基本とする。

■ DrScheme の環境と操作

処理系

知能情報工学科の計算機には、DrScheme がインストールされている。 DrScheme は、Scheme のプログラミング環境の一種である。 ここがDrSchemeのホームページである:http://www.drscheme.org/ Windows用もある。

主な操作方法

以下に主な操作方法を示す。
起動方法 コンソール上で drscheme を実行する
ウインドウ デフォルトでは幾つかのボタンと2つの白いエリアがある
上のエリア:式を定義するエリア (Definitions)
下のエリア:対話的に式を評価(実行)するエリア (Interactions)
メニューの中の「View」の中の項目を操作することでウインドウの設定が可能※1
マニュアル メニューの中の「Help」の中の「Help Desk」より検索が可能
プログラムの作成 Definitions に書き込む
プログラムの実行 Run ボタンを押した後、Interactions で、式を入力する(たとえば、関数に具体的な値を与える)
プログラムの保存 メニューの中の「File」の中の「Save Definitions」を選択する
プログラムの読み込み メニューの中の「File」の中の「Open」を選択する
終了方法 メニューの中の「File」の中の「Quit」を選択する

※ Interactions を表示するには、「メニュー」の中の「View」の中の「Show Interactions」を選択する。

Language の選択

DrScheme は習熟度に合せたプログラミングができるような配慮がされている。これからの演習では、「Standard」のレベルで演習を進めるので、以下の操作をしておくこと。

  1. メニューの中の「Language」をクリック
  2. 「Choose Language」をクリック
  3. Choose Language ウインドウの上から2行目の「Standard (R5RS)」をクリック
  4. 「OK」をクリック
  5. 「Run」ボタンをクリック

DrSchemeの操作画面

■ 式(フォーム)

式には次の種類がある:

■ 評価

評価のしかた:Interactions 上に、式を入力して、Enterキーを押す。

例題を見ながら「評価」について理解しよう。

□「定数」の評価

例題1

Interactions 上で、「定数」の式を評価してみよう。
> 100 ⇒ 100 が返り値となる。
> 3/4 ⇒ 分数を評価すると,3/4が返り値となる。
            Languageの選択によっては実数で返り値が表示される。
> 'hello ⇒ シンボルとしての hello が返り値となる。
> +   ⇒ 足し算の本体である #<primitive:+> が返り値となる。

□「コンビネーション」の評価

コンビネーションは、以下の形式となっている。
(〈式1〉  〈式2〉 〈式3〉 〈式4〉… 〈式n〉)

〈式1〉のことを、最左部分式と呼ぶ。コンビネーションの評価とは、〈式1〉から〈式n〉までを個別に評価した後で、最左部分式の評価結果(返り値)に、残りの式の評価結果を渡して評価する。

例題2

Interactions 上で、「コンビネーション」の式を評価してみよう。
> (+ 1 2) ⇒ 2項演算。
> (- 5) ⇒ 単項演算
> (sqrt 2) ⇒ 組み込み関数。√2 のこと。
> (+ (* 2 3) 4) ⇒ 中置記法では「 2 * 3 + 4」
> (* (+ 1 2) (- 3 (/ 4 5))) ⇒ 中置記法では「(1 + 2) * (3 - 4 / 5)」
> (sin (/ 3.141592653589793 2)) ⇒ 引数部に式を与えている。数学の記法では、sin(π/2) のこと。

□「変数」の評価

Scheme では、次の形式で、式に名前を付けることができる。
(define 〈名前〉 〈式1〉)

付けた名前は、変数として扱うことができる。なお、define を使ったこの式は、特殊形式の式である。

例題3

Interactions 上で、「変数」の作成とその評価をしてみよう。
> (define x 100) ⇒ これは特殊形式の評価。「100」の評価結果に「x」という名前を付けた。
> x ⇒ これは変数の評価。変数である x を評価すると、対応する式が返り値となる。
> (define san (+ 1 2)) ⇒ これは特殊形式の評価。「(+ 1 2)」の評価結果に san という名前を付けた。
      つまり、「3」に「san」という名前を付けた。
> san ⇒ これは変数の評価。変数である san を評価すると、対応する式(定数の式)が返り値となる。
> (define tasu +) ⇒ これは特殊形式の評価。「+」の評価結果(#<primitive:+>)に、tasu という名前を付けた。
> (tasu 1 2) ⇒ これは「コンビネーション」の評価。
> tasu ⇒ これは変数の評価。
> (tasu x san) ⇒ 全体はコンビネーションの評価。〈式1〉から〈式3〉までをそれぞれ評価して、
      〈式2〉と〈式3〉の評価結果を〈式1〉の評価結果に渡して評価してもらうので、100 と 3 を
      #<primitive:+> に評価してもらうことになる。

□「ラムダ式」の評価

変数を使った式を作りたいときには「ラムダ式」を使う。

ラムダ式は次の形式(特殊形式)である:
(lambda (〈引数1〉 〈引数2〉 〈引数3〉…) 〈式1〉 〈式2〉…〈式m〉)

〈引数〉のところに使用する変数を記入する。〈式1〉…〈式m〉 ではその変数を使うことができる。なお、〈式1〉…〈式m〉は、この時点では評価されない。

例題4

Interactions 上で、「ラムダ式」である式を評価してみよう。
> (lambda (x) (* x 3))
> ((lambda (x) (* x 3)) 4)

どちらの行とも、ラムダ式の部分は「xを3倍する」という意味である。

1行目の評価の結果は、手続き(procedure)であり、「xを3倍する処理の正体」である。

2行目の評価は、全体的に見れば「コンビネーションの評価」である。下線部の評価結果は「手続き」であるので、その手続きに「4」が渡される。ゆえに、返される値は 12 である。なお、返り値は、〈式m〉の評価結果である。

例題5

ラムダ式にも名前を付けることができる。
> (define sanbai (lambda (x) (* x 3)))
> (sanbai 4)


■ 練習

例題6

果物の名前と価格を定義し、その名前を使って、果物の代金を計算しよう。

価格は次のように設定しよう。

apple 110
orange 90
pineapple 230
peach 190

例として、apple 3つ、orange 5つ、pineapple 1つ、peach 5つの場合を計算しよう。


  1. Definitions で入力
    (define apple 110)
    (define orange 90)
    (define pineapple 230)
    (define peach 190)
    
  2. Runボタンを押す
  3. Interactions で評価
    > (+ (* apple 3) (* orange 5) (* pineapple 1) (* peach 5))
    

上記の定数の定義をファイル「prac0601.scm」に保存しよう。また、いったんdrscheme を終了し、再び起動して、定義ファイルを開いてみよう。

練習1

例題6の続きとする。贈り物用のフルーツセット(giftbox)には、メロンが1つ、林檎が5つ、オレンジが3つ入っている。メロンは単価が 800 円とする。giftbox の代金は、入っている果物の値段と箱代(box)50円の合計とする。giftbox の代金を定義しよう。

お得用フルーツセット(specialbox)には、1割引の桃が3つ、定価のパイナップルが1つ、2割引のオレンジが5つ入っている。specialbox の代金はそれらの果物の値段の和として箱代はサービスとする。specialbox の代金を定義しよう。

以上の定義を prac0602.scm に保存しよう。

練習2

次の式を計算するための関数を定義せよ。以下を prac0603.scm としてセーブしよう。

  1. f(x) = x2 + 5 x + 6
  2. g(x) = (x + 2)(x + 3)
  3. d(a,b,c) =「ax2 + bx +c が実数解を持つかどうかの判別式」
  4. heron(a,b,c) = 「3辺の長さが a b c である三角形の面積をヘロンの公式で求める。」
    ※ ヘロンの公式:s = (a + b + c)/2 とするとき、三角形の面積は sqrt(s * (s - a) * (s - b) * (s - c)) である。

ヒント1:ヘロンの公式を使うには、計算を2段階で行なう必要がある。すなわち、1段階目で s を求め、2段階目で、s を使った計算である。heron4(a,b,c,s) という関数を定義しておき、heron(a,b,c)はそれを呼び出すことにする。

ヒント2:ヒント1の方法では、関数 heron と関数 heron4 とが別々に定義されるので、関数の間の関係が弱くなる。そこで、ラムダ式の定義では複数の式を定義できることに注目する。すなわち、ラムダ式の〈式1〉の部分で s の計算結果に名前を付けておき、〈式2〉の部分で a, b, c, s を使った計算をすることにする。

ヒント3:ヒント1の方法において、heron4 を heron の中で展開しておく方法がある。すなわち、引数として、a, b, c, s を持つ関数のラムダ式を、引数 a, b, c を持つ関数のラムダ式が取り囲むように定義する。

答えはここ


(c) 2008.5.20 by tokuhisa