星田さんの記事に対するコメント。
今回はあくまで参考。
;; (range n) を利用してそこで計算を終わらせるパターン。
;; このパターンの take と dropは相互補完的になってて、;; 両者のエンジンはほぼ同じで、最終的に car を取るか;; cdr を取るか、と言うのが違い。
;;フィボナッチ数列のパターンを思い出すように。
;; いずれにせよ、 take の方がメンド臭い。
(define (take3 xn n)
(reverse (car (foldl (lambda (y x)
`(,(cons (cadr x) (car x)) . ,(cddr x)))
`(() . ,xn) (range n)))))
(define (drop3 xn n)
(cdr (foldl (lambda (y x)
`(,(cons (cadr x) (car x)) . ,(cddr x)))
`(() . ,xn) (range n))))
;; こっちは極端に見える take と やたらシンプルな drop のコンビ。;; take は前回のように call/cc で脱出するようにしてる。;; counter が n と等しくなった時、形成したリスト ls を持って脱出する。;; 反面、 drop はやたら簡単だ。n から作ったリストが空になったら;; xn を入れた初期値(リスト)が丁度良い具合に削られる。;; 何故、dropが簡単なのに take は手こずるのか、と言うのは;; foldl は基本的にはcdr-再帰の抽象化だから、だ。;; drop は cdr-再帰なんで、foldl と相性が良くて当然だ。(define (take4 xn n)
(call/cc
(lambda (return)
(foldl (lambda (y x)
(let ((count (car x)) (ls (cdr x)))
(if (= count n)
(return (reverse ls))
`(,(+ count 1) . ,(cons y ls))))) `(0 . ()) xn))))
(define (drop4 xn n)
(foldl (lambda (y x)
(cdr x)) xn (range n)))