だから、ここで説明されているように、多変量の ZipWithN を実装しようとしています。残念ながら、Paczesiowa のコードは ghc と HList の両方の古いバージョンでコンパイルされているようです。そのため、それがどのように機能するかを理解しようとする過程で、両方の最新バージョン (ghc-現時点では 7.8.3 および HList-0.3.4.1)。楽しかったです。
とにかく、中間関数の定義で、Googleが一度も修正するのを手伝ってくれないというバグに遭遇しましたcurryN'
。概念curryN'
は単純です: 型レベルの自然数N
(厳密に言えば、その型の値) と、f
最初の引数が length の HList である関数を取り、make HList を取る -ary 関数をN
返します。N
最初のN
引数のうち、そのf
HList に適用されたものを返します。ですcurry
が、多変量です。
3 つのヘルパー関数/クラスを使用します。
ここで定義したように、最初はResultType
/です。 単一の関数を引数として取り、その関数を必要な数の引数に適用した後、その関数の型を返します。(厳密に言えば、その型の未定義の値を返します)。resultType
resultType
例えば:
ghci> :t resultType (++)
resultType (++) :: [a]
ghci> :t resultType negate
resultType negate :: (ResultType a result, Num a) => result
(後者のケースは、a
たまたま type の関数だった場合x -> y
、 resultType は を返さなければならないためですy
。したがって、多相関数に完全に適用されるわけではありません。)
2 番目の 2 つはEat
/eat
とMComp
/で、こののように (壊れた とともに) 1 つのファイルでmcomp
一緒に (とともに) 定義されます。curryN'
curryN'
eat
の最初の引数は、型が自然数の値であり、引数を受け取り、それらを組み合わせて HList に返すN
関数を返します。N
ghci> :t eat (hSucc (hSucc hZero))
eat (hSucc (hSucc hZero)) :: x -> x1 -> HList '[x, x1]
ghci> eat (hSucc (hSucc hZero)) 5 "2"
H[5, "2"]
私が知る限り、それは完全に機能します。 mcomp
多変量構成関数です。これは と の 2 つの関数をf
取りg
、f
いくつかの引数を取りますN
。N
引数を取りf
、それらすべてに適用してからに適用g
する関数を返しますf
。(関数の順序(>>>)
は よりも並列(.)
)
ghci> :t (,,) `mcomp` show
(,,) `mcomp` show :: (Show c, Show b, Show a) => a -> b -> c -> [Char]
ghci> ((,,) `mcomp` show) 4 "str" 'c'
"(4,\"str\",'c')"
のようresultType
に、戻り値の型が型変数である関数では「中断」しますが、eat
(最終的な戻り値の型が単なるHList
) でのみ使用する予定なので、動作するはずです (Paczesiowa は少なくともそう考えているようです)。eat
の最初の引数が固定されている場合は、次のようになります。
\f -> eat (hSucc (hSucc hZero)) `mcomp` f
正常に動作します。
curryN'
ただし、次のように定義されます。
curryN' n f = eat n `mcomp` f
ただし、これを ghci にロードしようとすると、次のエラーが発生します。
Part3.hs:51:1:
Could not deduce (Eat n '[] f0)
arising from the ambiguity check for ‘curryN'’
from the context (Eat n '[] f,
MComp f cp d result,
ResultType f cp)
bound by the inferred type for ‘curryN'’:
(Eat n '[] f, MComp f cp d result, ResultType f cp) =>
Proxy n -> (cp -> d) -> result
at Part3.hs:51:1-29
The type variable ‘f0’ is ambiguous
When checking that ‘curryN'’
has the inferred type ‘forall f cp d result (n :: HNat).
(Eat n '[] f, MComp f cp d result, ResultType f cp) =>
Proxy n -> (cp -> d) -> result’
Probable cause: the inferred type is ambiguous
Failed, modules loaded: Part1.
明らかにeat
、mcomp
私が望んでいるほどうまく一緒にプレイしないでください。mcomp (+) (+1)
ちなみに、これは、 のインスタンスの重複について不平を言うエラーの種類とは大きく異なりますMComp
。
とにかく、このエラーに関する情報を見つけようとしても、何の役にも立たなかった - 私自身のデバッグの最大の障害は、どの型f0
にも現れないので、型変数が何であるかさえわからないことである.署名またはコンテキスト ghci が推測します。
私の最善の推測は、の多相的な戻り値の型を再帰するのmcomp
に問題があるということeat
です (それが型レベルの自然数によって修正されているにもかかわらず)。しかし、もしそうなら、私はそれを修正する方法がわかりません。
さらに(そして私には奇妙に)、 と をPart1.hs
単一Part2.hs
のファイルに結合しようとすると、まだエラーが発生します...しかし、別のファイルです
Part3alt.hs:59:12:
Overlapping instances for ResultType f0 cp
arising from the ambiguity check for ‘curryN'’
Matching givens (or their superclasses):
(ResultType f cp)
bound by the type signature for
curryN' :: (MComp f cp d result, Eat n '[] f, ResultType f cp) =>
Proxy n -> (cp -> d) -> result
at Part3alt.hs:(59,12)-(60,41)
Matching instances:
instance result ~ x => ResultType x result
-- Defined at Part3alt.hs:19:10
instance ResultType y result => ResultType (x -> y) result
-- Defined at Part3alt.hs:22:10
(The choice depends on the instantiation of ‘cp, f0’)
In the ambiguity check for:
forall (n :: HNat) cp d result f.
(MComp f cp d result, Eat n '[] f, ResultType f cp) =>
Proxy n -> (cp -> d) -> result
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘curryN'’:
curryN' :: (MComp f cp d result, Eat n [] f, ResultType f cp) =>
Proxy n -> (cp -> d) -> result
Failed, modules loaded: none.
再び謎のf0
型変数で。私はこのタイプハッカーのすべてについてここで少し頭を悩ませていることを認めます.うまくいけば、可能です)、私は信じられないほど感謝しています.
最後の注意: ここで 2 つのファイルが Part1 と Part3 と呼ばれる理由は、Part2 には で使用されるいくつかの補助関数が含まれていますが、 では使用されてzipWithN
いないためcurryN'
です。ほとんどの場合、それらは正常に機能しますが、後で尋ねるかもしれない奇妙な点がいくつかあります。