あなたが変更可能な変数を含むレキシカルスコープをキャプチャするために倍のカーネル関数を許可する場合、この問題が解決することができます。次に、アキュムレータタイプのBooleanを保持することができますが、計算を実行するのに十分な状態があります。
擬似コード:
(foldl (let ([s 0])
(lambda (accum item)
;; if (equal? item 1) and s is not already 2
;; increment s
;; return (equal? s 1)
)
#f list)
あなたはどのような環境をキャプチャしていない機能でこれを解決することはできません。なぜそれに制限するのですか?関数は、コードと定義上の字句環境です。上記で
、アキュムレータは、基本的にはダミーです。 s
という州は私たちが必要とするすべてを表しているので、私たちはそれを見ていません。ブールs
を使用して、状態がアキュムレータパラメータとs
の情報の組み合わせであるようにすることができます。ブールアキュムレータとブール値s
の間で状態を分割することができます(これらが一緒になって必要な3つの状態を表す2ビットカウンタを形成します)。ここで
は、それが変更可能な環境なしでちょうどブールを返す関数では解決できないという非公式の証拠である:
は、結果がブールなければならないことを観察:正確に一つ1
があり、正しいか間違っているか?したがって、フォールトカーネルとして使用する関数は、アキュムレータが返されるものなので、ブールアキュムレータを持つ必要があります。
フォールドのアキュムレータは、カーネル関数のアルゴリズムが決定を下す状態全体をカプセル化します。たとえば、関数が可変変数を含む字句スコープを使用すると、不正行為になります。
アルゴリズムでは、アキュムレータに少なくとも3つの状態が必要です。アキュムレータは、それが別の1
を見たとき、それはS2に移行し、そこから1
が分かるS1、に遷移そこからいくつかの初期S0、でなければなりません。このアキュムレータは、S0
と偽を示すS2
、そしてS1
が真となるように、折り返しの外側で解釈する必要があります。
理論的には訪問先アイテム間でアキュムレータタイプを変更することはできますが、これに関する情報はありません。どの要素が最後であるかは知らされていません。最後の要素を見ていることが分かっていれば、トライステートアキュムレータをブール値に戻してそれを返すことができます。
Sylwesterの答えの2番目の部分は継続を使用する理由はここにある:その後、代わりにS2への移行のアルゴリズムは、直接倍の外に脱出し、虚偽を生成することができます。アキュムレータはブール値になります。 (字句ブロックからの復帰などの完全な吹き飛ばされた継続の代わりに、はるかに単純な非局所的出口機構で十分である)。
出典
2016-10-04 19:02:50
Kaz