Skip to content

Instantly share code, notes, and snippets.

@nenono
Created April 21, 2015 08:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nenono/c19beee35a8a2103808c to your computer and use it in GitHub Desktop.
Save nenono/c19beee35a8a2103808c to your computer and use it in GitHub Desktop.
Schemeによるリスト処理関数のサンプル
;; 整数値からfizzbuzz結果の値に変換します。
(define (int->fizzbuzz x)
(let ((is-fizz (= (modulo x 3) 0)); 3で割り切れたらFizz
(is-buzz (= (modulo x 5) 0))); 5で割り切れたらBuzz
(let ((is-fizzbuzz (and is-fizz is-buzz))); FizzかつBuzzならFizzBuzz
(cond
(is-fizzbuzz "FizzBuzz")
(is-fizz "Fizz")
(is-buzz "Buzz")
(else x)))))
;; 指定された値までのfizzbuzzをコンソールに出力します。
(define (fizzbuzz max)
(*> (range 1 max); 1からmaxまでの範囲の整数のリストを生成
(map int->fizzbuzz); 全ての要素を整数からフィズバズ結果に変換
(iter print))); 全ての要素を順にコンソール出力
;; 関数合成
;; 複数の関数(f1, f2, f3...)を引数にとり、それを順に適用するような新しい関数を生成します。
;; つまり、(>> f1 f2 f3) == (lambda (x) (f3 (f2 (f1 x)))) というようなイメージ。
;; 可変長引数対応で複雑になっているので、実装それ自体はあまり気にしないでください。
(define >>
(lambda fs
(letrec
((>>
(lambda (fs)
(cond
((null? (cdr fs)) (car fs))
(else
(lambda (x)
((>> (cdr fs)) ((car fs) x))))))))
(>> fs))))
;; パイプライン演算子
;; 関数合成に加え、関数に最初に渡す値を指定します。
;; (*> x f1 f2 f3) == (f3 (f2 (f1 x))) というようなイメージ。
(define *>
(lambda (x . fs)
((call-with-values
(lambda () (apply values fs))
>>) x)))
;; 2引数関数の引数の順番を入れ替えます。
(define (flip f)
(lambda (x y) (f y x)))
;; listを先頭から走査し、順にアキュムレーター関数fを適用していき、その蓄積を返します。
;; fは2引数の関数で、第一引数に前回までの蓄積結果、第二引数に今回チェックする要素を取り、返り値として今回の蓄積結果を返します。
;; 参照: [List.fold<'T,'State> 関数 (F#)](https://msdn.microsoft.com/ja-jp/library/ee353894.aspx)
;; カリー化形式を模倣するため、listだけは最後に別で与える形とします。
(define (fold f init)
(letrec ((loop
(lambda (acc lis)
(cond
((null? lis) acc)
(else (loop (f acc (car lis)) (cdr lis)))))))
(lambda (lis) (loop init lis))))
;; listを逆順にします。
(define reverse
(fold (flip cons) '()))
;; listを先頭から走査し、順に関数fを適用していき、その結果を同じ順のリストにして返します。
;; カリー化形式を模倣するため、listだけは最後に別で与える形とします。
(define (map f)
(>>
(fold (lambda (acc x) (cons (f x) acc)) '())
reverse))
;; listを先頭から走査し、順に関数fを適用していき、その結果を破棄します。
;; カリー化形式を模倣するため、listだけは最後に別で与える形とします。
(define (iter act)
(fold (lambda (acc x) (begin (act x) #f)) #f))
;; initからmaxまでの整数のリストを生成します。
;; Scheme標準ではiota関数が知られています。
(define (range init max)
(cond
((< max init) '())
(else (cons init (range (+ 1 init) max)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment