labunix's blog

labunixのラボUnix

Scheme(gouche)を使ってみる。

■Scheme(gouche)を使ってみる。

$ sudo apt-get install -y gauche gauche-doc

$ dpkg -l | awk '$1 ~ /^ii/&&$2 ~ /^gauche/{gsub("   *",",",$0);print $0}'
ii,gauche,0.9.5-1,amd64,Scheme script engine

■マニュアルは日本語版がローカルで見れる。

$ info gauche-refj.info

■Hello World
 displayに直接渡すと、「#<undef>」が出たり「\n」を入れないといけなかったりするし、
 printでも「#<undef>」が出るので、
 そのまま評価するか、「x->string」を使う。

$ echo '"Gauche"'| gosh -i | sed -e 's/gosh> //g'
"Gauche"

$ echo '(x->string "Hello, World")' | gosh -i | sed -e 's/gosh> //g'
"Hello, World"1~nの総和の計算

$ echo '(define (fact n)
    (cond ((= n 0) 0)
          ((= n 1) 1)
          (else(+ n (fact (- n 1)))) ))
(fact 100)
' | gosh -i | sed -e 's/gosh> //g'
fac
5050

■seqと同様の動きをするiotaで書いてみる。

$ echo "(+ $(seq 1 100))" | gosh -i | sed -e 's/gosh> //g'5050

$ echo '(define (fact n)(fold + 0 (iota n 1)))(fact 100)' | gosh -i | sed -e 's/gosh> //g'
fact
5050

■goshのデバッグはtraceだけでは足りないので、以下のようにする。
 condはif文を重ねた動作をする。

 (use slib)(require \047trace)(trace fact)

$ echo -e '(define (fact n)
    (cond ((= n 0) 0)
          ((= n 1) 1)
          (else(+ n (fact (- n 1)))) ))
(use slib)(require \047trace)(trace fact)(fact 100)
' | gosh -i | sed -e 's/gosh> //g'
fact
#t
#<closure ((debug:trace-procedure debug:trace-procedure) . args)>
CALL fact 100
 CALL fact 99
  CALL fact 98
   CALL fact 97
    CALL fact 96
    RETN fact 4656
   RETN fact 4753
  RETN fact 4851
 RETN fact 4950
RETN fact 5050
5050

■ガウスの和算

$ echo "(+ (* 100 50) 50)" | gosh -i | sed -e 's/gosh> //g'
5050

$ echo '(define (fact n)
(/ (* (+ n 1) n) 2))
(fact 100)
' | gosh -i | sed -e 's/gosh> //g'
fact
5050

■階乗

$ echo -e '(define (fact n)
    (cond ((= n 0) 0)
          ((= n 1) 1)
          (else(* n (fact (- n 1)))) ))
(use slib)(require \047trace)(trace fact)(fact 10)
' | gosh -i | sed -e 's/gosh> //g'
fact
#t
#<closure ((debug:trace-procedure debug:trace-procedure) . args)>
CALL fact 10
 CALL fact 9
  CALL fact 8
   CALL fact 7
    CALL fact 6
    RETN fact 720
   RETN fact 5040
  RETN fact 40320
 RETN fact 362880
RETN fact 3628800
3628800

■フィボナッチ数列
 ものすごく非効率的なので、2桁を超える大きな数は扱わない方が良い。

$ echo '(define (fib n)
(cond ((= n 0) 0)
      ((= n 1) 1)
      (else (+ (fib (- n 1)) (fib (- n 2)))) ))
(map fib (iota 31))' | gosh -i | sed -e 's/gosh> //g'
fib
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040)

$ echo '(define (fib n)
(cond ((= n 0) 0)
      ((= n 1) 1)
      (else (+ (fib (- n 1)) (fib (- n 2)))) ))
(map fib (iota 31))' | gosh -i | sed -e 's/gosh> //g' -e '/fib/d' -e 's/(\|)//g' -e 's/ /\n/g' | nl -v 0
     0	0
     1	1
     2	1
     3	2
     4	3
     5	5
     6	8
     7	13
     8	21
     9	34
    10	55
    11	89
    12	144
    13	233
    14	377
    15	610
    16	987
    17	1597
    18	2584
    19	4181
    20	6765
    21	10946
    22	17711
    23	28657
    24	46368
    25	75025
    26	121393
    27	196418
    28	317811
    29	514229
    30	832040

■ネイピア数

$ echo "(exp 1)" | gosh -i  | sed -e 's/gosh> //g'
2.718281828459045

■tan(e)

$ echo "(tan (exp 1))" | gosh -i  | sed -e 's/gosh> //g'
-0.4505495340698077

■πの計算

 三角関数の逆関数で円周率 clisp
 https://labunix.hatenadiary.org/entry/20120101

 atan 1 = π/4、acos(-1) = π、asin(1) = π/2

■アークタンジェントによる円周率の計算

$ echo "(* 4 (atan 1))"  | gosh -i  | sed -e 's/gosh> //g'
3.141592653589793

■アークコサインによる円周率の計算

$ echo "(acos -1)"  | gosh -i  | sed -e 's/gosh> //g'
3.141592653589793

■アークサインによる円周率の計算

$ echo "(* -2 (asin -1))"  | gosh -i  | sed -e 's/gosh> //g'
3.141592653589793

■πを使った計算
 goshの起動時に読み込ませる際に関数から変数に変換してみる。
 個人的にはatanを使った公式の方が好みなのだけど、今回はacosで。

$ cat pi.scm 
(define (func-pi) (acos -1))
(define pi (func-pi))

$ gosh -l ./pi.scm
gosh> pi
3.141592653589793
gosh> (/ pi 2)
1.5707963267948966
gosh> (exit)

$ echo '(/ pi 2)' | gosh -i -l ./pi.scm | sed -e 's/gosh> //g'
1.5707963267948966

■上記が出来るなら直接変数にすれば良いということで。

$ cat pi2.scm 
(define pi (acos -1))

$ echo '(/ pi 2)' | gosh -i -l ./pi2.scm | sed -e 's/gosh> //g'
1.5707963267948966

$ echo '(/ (* (* pi pi)) 6)' | gosh -i -l ./pi2.scm | sed -e 's/gosh> //g'
1.6449340668482264

■円周の計算

$ echo '(* 2 pi 1)' | gosh -i -l ./pi2.scm | sed -e 's/gosh> //g'
6.283185307179586

■組み込みのlogを使う。

$ echo "(log 2)" | gosh -i  | sed -e 's/gosh> //g'
0.6931471805599453