foldLeft
フォールドに提供される初期値が完全にカリー化された関数であり、演算子がapply
であり、リストが関数に渡される引数のリストである場合、引数のリストに対して a を実行することは可能ですf
か?
たとえば、f が次のように定義されているとします。
scala> val f = (i: Int, j: Int, k: Int, l: Int) => i+j+k+l
f: (Int, Int, Int, Int) => Int = <function4>
もちろん、直接使用できます。
scala> f(1, 2, 3, 4)
res1: Int = 10
または、一度に 1 つずつ引数をカリー化して適用します。
scala> f.curried
res2: Int => Int => Int => Int => Int = <function1>
scala> f.curried.apply(1).apply(2).apply(3).apply(4)
res3: Int = 10
一見、これは の仕事のように見えfoldLeft
ます。
この一連のapply
使用方法を説明する最初の試みはfoldLeft
次のようになります。
scala> List(1, 2, 3, 4).foldLeft(f.curried)({ (g, x) => g.apply(x) })
ただし、次のエラーが発生します。
<console>:9: error: type mismatch;
found : Int => Int => Int => Int
required: Int => Int => Int => Int => Int
List(1, 2, 3, 4).foldLeft(f.curried)({ (g, x) => g.apply(x) })
エラーメッセージを読んだところ、型推論にはg
.
私が探しているソリューションでは、次のタイプを除いて、元の式のすべてが変更されていませんg
。
List(1, 2, 3, 4).foldLeft(f.curried)({ (g: ANSWER, x) => g.apply(x) })
私が最初に考えたのは、ユニオン型がここで役立つだろうということでした。Miles Sabin が Curry-Howard を使用して共用体型を導出するのを見たことがあります。そのため、最初の予感が正しければ、問題を解決するために必要な基本的な機構を持っているように見えます。
ただし、ユニオン型が答えであっても、「関数の完全にカリー化された型からカリー化された関数の型までのすべての型の結合で、最後の引数がすべて提供されている」を参照できれば便利です。つまり、型を変える方法は次のとおりです。
T1 => ... => Tn
ユニオンタイプに:
(T1 => ... => Tn) |∨| ... |∨| (Tn-1 => Tn)
上記のタイプとして役立ちg
ます。
a foldLeft
on a を実行すると、すべてが同じList
である場合にのみ議論が制限T1
されます。Tn-1
みたいな表記
(T1 =>)+ Tn
に提供したいタイプを説明しますg
。
私が尋ねている特定のケースでは、任意の長いチェーンは必要ないため、次を使用してイテレータに境界を提供できます
(T1 =>){1,4} Tn
ただし、等しくない型のチェーンに対してこれを実行したい場合は、チェーンをすべての接尾辞のセットに切り刻む型の魔法の関数の方が便利かもしれません。
Suffixes(T1 => ... => Tn)
これを実装することは、現時点で私の Scala の能力をはるかに超えています。そうする方法についてのヒントをいただければ幸いです。これが、Scala の既存の型システムを高度に使用するか、コンパイラ プラグインを介して実行できるか、またはそのどちらでもないかはわかりません。
以下のコメントで指摘されているように、結果を「共用体型」と呼ぶことは、このユース ケースには完全に適合しません。他に何と呼べばいいのかわかりませんが、それが現時点で最も近いアイデアです。他の言語はこの考えを特別にサポートしていますか? これは Coq と Agda でどのように機能しますか?
この問題に名前を付けて、全体像 (型理論、決定可能性など) に関してどこに位置するかを理解することは、 の実用的な実装を持つことよりも重要ですがANSWER
、どちらも良いことです。Scalaz、Monoids、または圏論全般への接続を描くことができる人にはボーナス ポイントがあります。