練習:init、inits、tail、tails

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>

どういうこと?

「練習:init、inits、tail、tails」への2件のフィードバック

  1. #0=等の表記は共有構造を明示するLispの(Common Lispでは標準、Schemeではsrfi-38)表記です。 ((1 . #0=(2)) #0#) というのは、 ((1 2) (2)) の最初のリストのtail部分(2)が、二番目のリスト(2)と共有されていることを示します。

    1. ということは、単純な ((1 2) (2)) とはデータとして構造が違うということですね。
      ご教示ありがとうございます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください