高階関数のポイントは、コード内のボイラープレートを削減し、ループ (技術的には再帰ですが、その目的はループであるため、そのように言及します) と実際のロジックの間の結合を減らすことです。例を次に示します (すべての奇数を再取得します): 手動ループは次のようになります。
(define (filter-odd lst)
(cond ((null? lst) '())
((odd? (car lst)) (cons (car lst) (filter-odd (cdr lst))))
(else (filter-odd (cdr lst)))))
しかし、ループとフィルタリングが 1 つの関数で行われていることに注意してください。これらの 2 つの無関係な操作が結合されているため、関数が何を行っているかを把握するのが難しくなります。高レベル関数を使用すると、別の方法で実行できます。
(define (filter pred lst)
(cond ((null? lst) '())
((pred (car lst)) (cons (car lst) (filter pred (cdr lst))))
(else (filter pred (cdr lst)))))
(define (filter-odd lst)
(filter odd? lst))
odd?
ここで、が に分離されたループ ロジックからどのように分離されているfilter
かに注目してください。filter
アイテムを保持するかどうかを決定する関数オブジェクトを受け取るようになり、 の呼び出し元filter
は、選択した任意の関数を挿入できます。
これが高階関数の意味です。これは、関数オブジェクトをパラメーターとして取り、その操作をカスタマイズする関数です。
あなたの質問の元の編集で述べたように、map
別の高次関数ですが、リストからアイテムをフィルタリングする代わりに、元のリスト内のすべてのアイテムの変換を返します。特定の変換は、map
の呼び出し元によってパラメータ。
フラット化などに関する実際の質問に答えるに(map filter-odd '((1 3 (9 5 7))))
は、 を呼び出した結果である単一のアイテムを含むリストが返され(filter-odd '(1 3 (9 5 7)))
ます。いいえ、map
あなたのためにサブリストに再帰しません(そしてどちらもしませんfilter
)。
ただし、最初に入力を平坦化して (とにかく出力を平坦化するため)、それfilter-odd
を直接呼び出すことができます。期待どおりの結果が得られることを願っています。
((述語)と混同される可能性が低いため、名前を your に変更odd
しました。)filter-odd
odd?
おまけ素材
ちなみに、filter
とmap
は両方とも、フォールド (より具体的には右フォールド) と呼ばれる、より一般的な高階関数の特殊化です。filter
折り畳みは、またはでは対応できないことを表現できますmap
が、何らかの形でリスト内のすべての項目をトラバースする必要があります。length
フォールドとして表現された関数の例を次に示します。
(define (foldl func init lst)
(if (null? lst) init
(foldl func (func (car lst) init) (cdr lst))))
(define (length lst)
(foldl (lambda (elem count)
(+ count 1))
0 lst))
ここでの利点は、length
関数がリストのトラバースについて心配する必要がないことです。これはフォールドによって処理されます。各反復で何をすべきかを気にする必要があるだけです (ここでは、count
0 から始まる に 1 を追加するだけです)。
この場合、左からトラバースしても右からトラバースしても長さは同じであり、Scheme では左からトラバースした方がスペース効率が良いため、その方が好ましい。map
ただし、 andを実装するにfilter
は、右折が必要です (そうしないと、要素が逆になります。以下の関数でfoldr
withfoldl
を置き換えてみてください)。
(define (foldr func init lst)
(if (null? lst) init
(func (car lst) (foldr func init (cdr lst)))))
(define (map func lst)
(foldr (lambda (elem result)
(cons (func elem) result))
'() lst))
(define (filter pred lst)
(foldr (lambda (elem result)
(if (pred elem)
(cons elem result)
result))
'() lst))