技術memo

関数型ゴースト

Scheme(Gauche)でポイントフリースタイル風味

;; リスト(ツリー)を平坦化する。
(define flatten
  (letrec ((flatten-rev
            (fold$
             (lambda (x acc)
               (if (list? x)
                   ;; xがlistなら再帰呼び出し結果をaccの先頭に追加
                   ((compose (fold$ cons acc) reverse flatten-rev) x)
                   ;; それ以外なら単にxをaccの先頭に追加
                   (cons x acc)))
             '())))
    (compose reverse flatten-rev))); 最終的に正しい順(逆順)にする
;; test
(equal?
 (flatten '((1 2 3) 4 5 (6 (7 8))))
 '(1 2 3 4 5 6 7 8))
;; #t
  • 動作環境はGauche 0.9.4です。
  • composeは関数合成です
    • 先日再発明しました。*1
    • 実は組み込みで存在しました。
    • ですが、関数の記述順が逆順です。*2
  • 関数の部分適用では、cutマクロが便利そうです。
  • また、pa$関数は、関数の部分適用ができます。
    • Gauche ユーザリファレンス: 6.18 手続きと継続 参照。
    • curry化ではないので、
      • ((pa$ cons 1) '(2))はできても、(=> (1 2))
      • (((pa$ cons) 1) '(2))はできません。
    • 使い方説明にもありますが、引数は最初の引数から適用されます。
      • ((pa$ string-append "a" "b") "c" "d") => "abcd"
  • 先日の記事でもmap$, filter$, for-each$等のリスト処理関数を使っていますが、大体このあたりを把握しておけば、まずまず関数型スタイルなプログラミングができそうです。
    • 「やりすぎ危険」な症状が既に出ている感じもありますが。

*1:SchemeでF# 風パイプライン演算子を書いてみた - 技術memo

*2:それに気づかずにデバッグに時間がかかってしまいました。

*3:まあ普通に考えて無理そうです。