所以,我正在尝试实现一个多变量 ZipWithN,如此处所述。不幸的是,Paczesiowa 的代码似乎是用过时版本的 ghc 和 HList 编译的,所以在试图理解它是如何工作的过程中,我也一直在将它移植到这两个版本的最新版本(ghc- 7.8.3 和 HList-0.3.4.1)。这很有趣。
无论如何,我在中间函数的定义中遇到了一个谷歌没有帮助我修复的错误curryN'
。从概念上讲,curryN'
很简单:它接受一个类型级别的自然数N
(或者,严格来说,该类型的值)和一个函数f
,其第一个参数是一个长度为 HList 的函数N
,并返回一个N
-ary 函数,该函数接受一个 HList出它的第一个N
参数,并返回f
应用于该 HList。是curry
,但是是多变量的。
它使用三个辅助函数/类:
第一个是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
。所以它并不完美地应用于多态函数。)
后两个是Eat
/eat
和MComp
/ ,像这样mcomp
一起定义(连同curryN'
)在单个文件(连同损坏的curryN'
)中。
eat
的第一个参数是一个类型为自然数的值N
,并返回一个函数,该函数接受N
参数并将它们组合成一个 HList:
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
是一个多变量组合函数。它需要两个函数,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
通过 's 的多态返回类型进行递归时遇到了麻烦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
类型变量。我承认我对所有这些 typehackery 有点不知所措,所以如果有人能帮我弄清楚这里到底是什么问题,更重要的是,我该如何解决它(如果是的话,希望,可能),我将非常感激。
最后说明:这里的两个文件之所以叫Part1和Part3,是因为Part2里面有一些辅助函数用到了zipWithN
,而没有curryN'
。在大多数情况下,它们工作正常,但我稍后可能会问一些奇怪的问题。