質問

私は何に苦労しています スーパーコンビネーター それは:

スーパーコンビネーターは、サブエクスペーションとしてのスーパーコンビネーターのみを含む定数またはコンビネーターのいずれかです。

また、何で 一定の適用フォーム それは:

ラムダ抽象化ではないスーパーコンビネーター。これには、12、(+)1 2)、[1,2,3]などの真に一定の式と、((+)4)などの部分的に適用された関数が含まれます。この最後の例は、 x->(+)4 xにcafではない x->(+)4 xに等価であることに注意してください。

これは私には意味がありません!そうではありません ((+) 4) 12と同じくらい「本当に一定」? CAFは私のシンプルな心の価値のように聞こえます。

役に立ちましたか?

解決

参照するこれらのHaskell Wikiページは古いものであり、残念ながら書いたと思います。特に不幸なのは、彼らがCAFとスーパーコンビネーターを混ぜ合わせることです。スーパー団体は興味深いが、GHCとは無関係です。 CAFは依然としてGHCの一部であり、スーパーコンビネーターに言及することなく理解できます。


それでは始めましょう スーパーコミネーター. 。組み合わせはから派生します 組み合わせロジック, 、そして、ここでの使用では、互いに渡された値を一方または別の形式でのみ適用する関数で構成されています。つまり、彼らは彼らの引数を組み合わせます。最も有名な組み合わせセットはです s、k、およびi, 、一緒に取られているのは、チューリングが完全です。このコンテキストでは、スーパーコミネーターは、渡された値、組み合わせ、およびその他のスーパー団体のみで構築された関数です。したがって、スーパーコンビネーターは、置換を通じて、単純な古い組み合わせに拡張できます。

関数言語の一部のコンパイラ(GHCではなく!)は、コンビネーターとスーパーコンビネーターをコンパイルの中間ステップとして使用します。同様のコンパイラテクノロジーと同様に、これを行う理由は、このような単純化された最小言語でより簡単に実行される最適化分析を認めることです。スーパー契約者の上に構築されたそのようなコア言語の1つは、エドウィンブレイディのものです 大作.


一定の適用フォーム まったく別のものです。彼らはもう少し微妙で、いくつかのゴッチャを持っています。それらを考える方法は、独立した意味的な意味がなく、ランタイムパフォーマンスに潜在的に深い影響を与えるコンパイラ実装の側面としてです。以下はCAFの完全な説明ではないかもしれませんが、それは私が見たことがないので、私の直感を伝えようとします。 本当 良い説明私がベビーベッドからするための他の場所。 GHCの解説wikiでの「権威ある」説明をきれいにする 次のように読み取ります:

一定の適用フォーム、または略してCAFはプログラムで定義されているトップレベルの値です。基本的に、それらは実行時に動的に割り当てられていないが、代わりにプログラムの静的データの一部であるオブジェクトです。

それは良いスタートです。純粋で機能的で怠zyな言語は、ある意味でグラフ還元マシンと考えることができます。ノードの値を初めて要求するときは、評価を強制し、サブノードなどの値を要求する可能性があります。 持ってる 固執するために - これは純粋な言語であるため、セマンティック効果なしでサブノードを常にライブに保ち、再計算することができます)。 CAFは確かに単なる価値です。しかし、文脈では、特別な種類の価値 - コンパイラーが決定できる価値は、そのサブノードに完全に依存する意味を持っています。つまり、

foo x = ...
  where thisIsACaf = [1..10::Int]

        thisIsNotACaf = [1..x::Int]
        thisIsAlsoNotACaf :: Num a => [a]
        thisIsAlsoNotACaf = [1..10] -- oops, polymorphic! the "num" dictionary is implicitly a parameter.

        thisCouldBeACaf = const [1..10::Int] x -- requires a sufficiently smart compiler
        thisAlsoCouldBeACaf _ = [1..10::Int] -- also requires a sufficiently smart compiler

では、なぜ物事がカフェであるかどうかを気にするのですか?基本的に、私たちは本当に何かを再計算したくないことが本当にありません(たとえば、Memotable!)、それが適切に共有されていることを確認したいからです。それ以外の場合は本当に 行う 何かを再計算したい(たとえば、私たちが歩いているだけのナチュラルなどの巨大な退屈なリストを生成するのは、それを歩いているだけです)。物事を命名し、それらをインラインの下に結合したり、それらを書いたりすることなどの組み合わせにより、通常、これらの種類のものを自然で直感的な方法で指定することができます。ただし、時折、コンパイラは予想よりも賢くまたは馬鹿げている場合があり、一度に計算されるべきだと思うものは、常に再計算されるべきか、やりたくないものがカフェとして持ち上げられたくないものです。次に、もっと慎重に物事を考える必要があります。この議論を参照して、関係するトリッキーのいくつかについてのアイデアを得る: 「共有」を避ける良い方法は?

ちなみに、私はそれを感じていませんが、既存のHaskell Wikiページと統合して、それらを改善/更新したいのと同じくらい、この答えを自由に受け取ることを望んでいる人なら誰でも

他のヒント

マットは、定義が混乱しているという点で正しいです。それは矛盾しています。 CAFは次のように定義されています。

ラムダ抽象化ではないスーパーコンビネーター。これには、次のような本当に一定の式が含まれます 12, ((+) 1 2), [1,2,3] などの部分的に適用された関数と同様に ((+) 4).

したがって、 ((+) 4) CAFと見なされています。しかし、非常に次の文章では、CAFではないものと同等であると言われています。

この最後の例は、ETA抽象化の下で同等です \ x -> (+) 4 x これはCAFではありません。

ラムダの抽象化と同等であるという地上で部分的に適用された関数を除外することはよりクリーンです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top