labunix's blog

labunixのラボUnix

AWSでLISP(gcl/sbcl)が使えるようにする。

■AWSでLISP(gcl/sbcl)が使えるようにする。
 手元のjessie環境ではclispがあるが、wheezyからのアップデート版だからのようだ。

$ dpkg -l clisp | awk '/^ii/{print $2,$3}'
clisp 1:2.49-8.1

■公式ページでパッケージを確認するとclispには「stable」なパッケージが無い。

 clisp
 https://packages.qa.debian.org/c/clisp.html

■今後の事も考えて、パッケージは「contrib」「non-free」を追加。
 これは飛ばしても良い。

$ sudo sed -i -e 's/main$/& contrib non-free/g' /etc/apt/sources.list
$ sudo apt-get update
$ sudo apt-get install -y apt-file
$ sudo apt-file update

■clispの代わりにGCLとSBCLをインストール
 「-q」オプションが無いだけでなく、
 組み込み関数を使うときは特に、clispとは別の処理系と考えた方が良い。
 なお、SBCLの方が定義されていない関数というエラーでよく停止する。

$ sudo apt-get install -y hyperspec w3m gcl sbcl

$ echo "(+ `seq 1 100`)" | gcl | grep -v "^[A-z]\|^\$"
>
5050
>
$ echo "(+ `seq 1 100`)" | sbcl | grep -v "^[A-z]\|^\$"
* 
5050
* 

■Πのような組み込み関数だと表示結果は大きく異なる。
 結果そのものは解釈の違いなので良いが、表示結果が異なるので、
 今後は有効桁数やフォーマットには十分注意する必要がありそうだ。
 他にもclispの「EXT:LONG-FLOAT-DIGITS」等はエラーになるか無視される。

$ echo "(float pi)" | sbcl | tail -3;echo
* 
3.141592653589793d0
* 
$ echo "(float pi)" | gcl | tail -3;echo
3.141592653589793

>

$ echo "(float pi)" | clisp -q
[1]> 
3.1415926535897932385L0

■Hello World
 さすがにこの程度の関数で結果が異なる処理系なら使わない方が良い。

$ echo '(format t "Hello World")' | gcl  | grep -v "^[A-z]\|^\$"
>Hello World
>
$ echo '(format t "Hello World")' | sbcl  | grep -v "^[A-z]\|^\$"
* Hello World
* 

■再帰テスト

 clispの再帰で要素が10個で0から9までの等差数列の和をトレースする。
 http://labunix.hateblo.jp/entry/20150408/1428500494

$ echo '(defun fact (n)(if (= n 0) n (+ n (fact (- n 1)))))(fact 9)' | \
  gcl | grep -v "^[A-z]\|^\$"
>
>
45
>

$ echo '(defun fact (n)(if (= n 0) n (+ n (fact (- n 1)))))(fact 9)' | \
sbcl | grep -v "^[A-z]\|^\$"
* 
* 
45
*

$ echo '(defun fact (n)(if (= n 0) n (+ n (fact (- n 1)))))(trace fact)(fact 9)' | \
  gcl | grep -v "^[A-z]\|^\$"
>
>
(FACT)
>
  1> (FACT 9)
    2> (FACT 8)
      3> (FACT 7)
        4> (FACT 6)
          5> (FACT 5)
            6> (FACT 4)
              7> (FACT 3)
                8> (FACT 2)
                  9> (FACT 1)
                    10> (FACT 0)
                    <10 (FACT 0)
                  <9 (FACT 1)
                <8 (FACT 3)
              <7 (FACT 6)
            <6 (FACT 10)
          <5 (FACT 15)
        <4 (FACT 21)
      <3 (FACT 28)
    <2 (FACT 36)
  <1 (FACT 45)
45
>

$ echo '(defun fact (n)(if (= n 0) n (+ n (fact (- n 1)))))(trace fact)(fact 9)' | \
  sbcl | grep -v "^[A-z]\|^\$"
* 
* 
(FACT)
*   0: (FACT 9)
    1: (FACT 8)
      2: (FACT 7)
        3: (FACT 6)
          4: (FACT 5)
            5: (FACT 4)
              6: (FACT 3)
                7: (FACT 2)
                  8: (FACT 1)
                    9: (FACT 0)
                    9: FACT returned 0
                  8: FACT returned 1
                7: FACT returned 3
              6: FACT returned 6
            5: FACT returned 10
          4: FACT returned 15
        3: FACT returned 21
      2: FACT returned 28
    1: FACT returned 36
  0: FACT returned 45
45
* 

■素数判定(エラトステネスの篩)
 ※Wikiのコピペ
 https://ja.wikipedia.org/wiki/%E7%B4%A0%E6%95%B0%E5%88%A4%E5%AE%9A
 
$ echo "(defun eratosthenes (n)
  (labels ((foo (i ls)
                (if (= i 1)
                    ls
                  (foo (1- i) (cons i ls))))
           (spam (ls0 ls1)
                 (if (> (expt (car ls1) 2) (car (last ls0)))
                     (revappend ls1 ls0)
                   (let ((ls2
                          (remove-if #'(lambda (x)
                                         (zerop (mod x (car ls1))))
                                     ls0)))
                     (spam (cdr ls2) (cons (car ls2) ls1))))))
          (let ((lst (foo n nil)))
            (spam (cdr lst) (list (car lst))))))
(eratosthenes 1000)" | sbcl | tail -12
ERATOSTHENES
* 
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103
 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313
 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433
 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563
 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673
 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811
 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941
 947 953 967 971 977 983 991 997)

$ echo "(defun eratosthenes (n)
  (labels ((foo (i ls)
                (if (= i 1)
                    ls
                  (foo (1- i) (cons i ls))))
           (spam (ls0 ls1)
                 (if (> (expt (car ls1) 2) (car (last ls0)))
                     (revappend ls1 ls0)
                   (let ((ls2
                          (remove-if #'(lambda (x)
                                         (zerop (mod x (car ls1))))
                                     ls0)))
                     (spam (cdr ls2) (cons (car ls2) ls1))))))
          (let ((lst (foo n nil)))
            (spam (cdr lst) (list (car lst))))))
(eratosthenes 1000)" | gcl | tail -12
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181
 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277
 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383
 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487
 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601
 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709
 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827
 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947
 953 967 971 977 983 991 997)