Haskell にある関数を Scheme で書いてみた。
init
Haskell
Prelude Data.List> init [1,2,3,4,5] [1,2,3,4]
Scheme
(define init (lambda (lis) (take lis (- (length lis) 1)))) (print (init '(1 2 3 4 5)))
^o^ > gosh init.scm (1 2 3 4)
inits
Haskell
Prelude Data.List> inits [1,2,3,4,5] [[],[1],[1,2],[1,2,3],[1,2,3,4],[1,2,3,4,5]]
Scheme
(define inits (lambda (lis) (define f (lambda (n m l) (cond ((< n m) (quote ())) (else (cons (take l m) (f n (+ m 1) l)))))) (f (length lis) 0 lis))) (print (inits '(1 2 3 4 5)))
^o^ > gosh inits.scm (() (1) (1 2) (1 2 3) (1 2 3 4) (1 2 3 4 5))
tail
Haskell
Prelude Data.List> tail [1,2,3,4,5] [2,3,4,5]
Scheme
(define tail cdr) (print (tail '(1 2 3 4 5)))
^o^ > gosh tail.scm (2 3 4 5)
tails
Haskell
Prelude Data.List> tails [1,2,3,4,5] [[1,2,3,4,5],[2,3,4,5],[3,4,5],[4,5],[5],[]]
Scheme
(define tails (lambda (lis) (cond ((null? lis) (cons '() '())) (else (cons lis (tails (cdr lis))))))) (print (tails '(1 2 3 4 5)))
^o^ > gosh tails.scm ((1 2 3 4 5) (2 3 4 5) (3 4 5) (4 5) (5) ())
上のように、うまくいってるように見える Scheme の tails だけど、インタラクティブモードで定義して評価してやると変な値が返ってくる。
^o^ > gosh gosh> (define tails (lambda (lis) (cond ((null? lis) (cons '() '())) (else (cons lis (tails (cdr lis))))))) tails gosh> (tails '(1 2 3 4 5)) ((1 . #0=(2 . #1=(3 . #2=(4 . #3=(5))))) #0# #1# #2# #3# ())
最後の行が (tails '(1 2 3 4 5))
の変な値。
ところが、これを (print ...)
としてやるとちゃんとした値が出力される。
gosh> (print (tails '(1 2 3 4 5))) ((1 2 3 4 5) (2 3 4 5) (3 4 5) (4 5) (5) ()) #<undef>
どういうこと?
#0=等の表記は共有構造を明示するLispの(Common Lispでは標準、Schemeではsrfi-38)表記です。 ((1 . #0=(2)) #0#) というのは、 ((1 2) (2)) の最初のリストのtail部分(2)が、二番目のリスト(2)と共有されていることを示します。
ということは、単純な ((1 2) (2)) とはデータとして構造が違うということですね。
ご教示ありがとうございます。