Scheme とは?
コンピュータのプログラム言語です。
他のコンピュータ言語との比較
- 1957 Fortran
- 1958 Lisp
- 1959 COBOL
- 1972 Smalltalk
- 1972 C
- 1975 Scheme
- 1985 C++
- 1991 Python
- 1995 Javascript
- 2006 Scratch
いつ最初のリリースされたかというリストです。Scheme は Lisp から派生しています。このうち、C,Scheme,Python で書いたFizzBazzプログラムで比較してみましょう。
FizzBazz とは以下のようなゲームです。
- 1~100の数を出力します
- ただし、数が3の倍数の場合は数字の代わりに 「Fizz!」 を出力します。
- また、数が5の倍数の場合は数字の代わりに 「Buzz!」 を出力します。
- もし、数が3と5の公倍数の場合は数字や 「Fizz!」 や 「Buzz!」 の代わりに 「Fizz Buzz!」 を出力します。
#include <stdio.h>
main(){
int i;
for ( i=0, i<101, i++){
if ( 0 == i % 15) {
printf("Fizz Buzz!\n")
} else if ( 0 == i % 3) {
printf("Fizz!\n")
} else if ( 0 == i % 5) {
printf("Buzz!\n")
} else {
printf("%d\n",i);
}
}
for i in range(1, 101):
if 0 == i % 15:
print("Fizz Buzz!")
elif 0 == i % 3:
print("Fizz!")
elif 0 == i % 5:
print("Buzz!")
else:
print(i)
c と python は同じような感じですね。それに対し、
(define (ch x)
(define (p? n) (zero? (modulo x n)))
(cond ((p? 15) "FizzBuzz\n") ((p? 3) "Fizz\n") ((p? 5) "Buzz\n") (else x)))
(display (map ch (cdr (iota 101))))
(この scheme プログラムは)
「FizzBuzz問題あれこれ」
https://qiita.com/ytaki0801/items/1309b33d55d106d84bd5
から改変)
かなり違いますね!
これは前者2つの C と Python は手続き型という考え方でプログラムをしているのに対し、Scheme は関数型という考え方でプログラムを作っているからです。
なんとなく、手続き型だと直感で何をしているか読めますよね。それに対し scheme はよくわからないですね。カッコがたくさんあります。
一体何がいいのでしょうか?
Scheme のメリット
- 覚えることが少ない
- プログラミングの本質を学びやすい
- パズルみたいに楽しい
覚えることが少ないということはプログラムの本質に近いということです。
デメリット
しかしながら Scheme は独特? の考え方があるので、一旦は Scheme 流に慣れてしまう必要があります。
先のプログラムにはカッコがいっぱいありましたね。カッコ対応のエディターが必須となります。
インストールしてみよう!
MS-Windows
https://practical-scheme.net/gauche/
こちらから、 gauche をダウンロードして、インストールしてみましょう。
Linux
Linux のうち、 Ubuntu の場合は以下で解説しています。
「Gauche を Ubuntu にインストール (also macos ?)」
https://qiita.com/nanbuwks/items/96be3e9e0fe986f490e2
Mac
以下を試してみてください。
「Gauche を Ubuntu にインストール (also macos ?)」
https://qiita.com/nanbuwks/items/96be3e9e0fe986f490e2
起動してみる
MS-Windowsの場合はプログラムに登録されているのでGaucheを探して起動します。
Ubuntu や macos の場合は、ターミナルから以下のようにして起動します。
$ gosh
(Linux/Macの場合)
gosh>
この、対話環境をREPLといいます。(Read Eval Print Loop)
終了方法は、(exit) です
計算してみよう
gosh> (+ 1 2)
3
おお、ポーランド記法だ。
演算子として、基本的な以下のものは四則演算として使えます。
+ - * /
練習
さて、以下のようにするとエラーとなります。どうしたらいいかな?
gosh> (+ 1 2 * 3 4 )
(ヒント:括弧)
除算と分数
/ の計算をしてみましょう!
gosh> ( / 4 5 )
とすると、
4/5
と出てきます。 Scheme は珍しく分数が扱える言語です。
以下のように扱います。
gosh> ( + 2/3 5/3)
7/3
ここの 2/3 は 2 ÷ 3 の除算を表しておらず、数字としての $ \frac{2}{3} $ を表しています。
もし、同じことを除算で表すとこのようになります。
gosh> ( + ( / 2 3) (/ 5 3) )
7/3
分数を少数に直したい時は以下のようにします。
gosh> (inexact ( / 4 5 ))
0.8
S式
このような式をS式といいます。
( + 1 2 )
動作(関数) データ1(引数1) データ2(引数2)
正確には、関数と手続きという細かな区分けがあるのですが、ここでは全部まとめて関数とします。今まで関数として出てきたものは
- +
- -
- *
- /
- inexact
で、上記は数字を返すものです。それ以外にも、数字以外を返すものも含め以下のようなものもあります。(主要なもののみ紹介)
- 等しいかどうかを調べる
eqv?, eq?, equal? - 分数-小数変換
inexact, exact - 画面出力
display - 実数演算
exp, log, sin, cos, tan asin, acos, atan, square, sqrt, - ...
全部の関数は以下の記事で紹介しています。
「Scheme の標準手続一覧」
https://qiita.com/nanbuwks/items/e717b08c1551b84d7846
練習
- 比較をしてみましょう。
- 比較はたくさんありますが、( eqv? / eq? / equal? )とりあえず equal? を使ってみよう。
関数を定義してみよう!
gosh> (define ( length x y ) ( sqrt ( + (* x x)(* y y))))
これは
(define ( 変数 ) ( 式 ))
という構造です。
gosh> (length 3 4 )
5
横と縦の辺が 3 と 4 の直角三角形の斜辺の長さです。
練習
BMI (Body Mass Index) を求める関数を作ってみましょう。
BMIを求める式は以下のとおりです。
BMI = 体重 [kg] / ( 身長 [m] の自乗 )
理想的な BMI は 22です。
身長 を cm で入力できるようにしてみましょう。
変数を使ってみよう!!
gosh> ( define a 1 )
リストを使ってみよう!
Scheme はリストという形式でデータなどを管理します。
リストは、複数の値を1つにまとめますが、一番基本的な2つの値だけを持つリストとしてペアがあります。実際はリスト自体もペアの組み合わせで作られています。
gosh> (cons 1 2)
(1 . 2)
この操作で、1 と 2 のデータのペアを作ります。
cons は、ペアを作るために 2つの引数を与えます。
もし、以下のように1つの引数だけを取った場合は
gosh> (cons 1 )
*** ERROR: wrong number of arguments: cons requires 2, but got 1
While compiling "(standard input)" at line 1: (cons 1)
Stack Trace:
_______________________________________
0 (eval expr env)
at "/usr/share/gauche-0.9/0.9.6/lib/gauche/interactive.scm":267
エラーになります。
もし、1つの値だけを持つペアを作りたい場合は、2つ目の値の代わりに `()
を使います。
gosh> (cons 1 '())
(1)
ペアの中身も、ペアにすることができます。
gosh> (cons 1 (cons 2 '()))
(1 2)
どんどんつなげていくことができます。
gosh> (cons 1 (cons 2 (cons 3'())))
(1 2 3)
カッコがうしろにいっぱいになりますね。
これはこのように書くこともできます。
gosh> (cons 1 (
cons 2 (
cons 3'()
)))
一番最後のカッコはまとめて書くのが慣習です。
さて、 ( 1 2 3 )
というものを作りましたがこれは3つの値を持ったリストになります。
今回は上記のようにペアを組み合わせてリストを作りましたが、一気にリストを作る場合は
gosh> (list 1 2 3 )
(1 2 3)
で作成できます。
練習
Jan. Feb. Mar. という文字列を含んだリストを Month という名前で作成しましょう。
文字列は " で囲みます。
IFを使ってみよう
(if predicate then_value else_value)
比較はとりあえず equal? を使うようにしましょう。
gosh> (equal? 1 1 )
#t
( if (equal? 1 1 ) (display "OK") (display "BAD"))
OK#<undef>
比較
gosh> ( compare 1 2 )
-1
gosh> ( compare 2 1 )
1
gosh> ( compare 2 2 )
0
練習
身長と体重を入力して、BMIが18.5~25であれば適正体重であることを表示する関数を作ってみましょう。
(以降執筆中です)