所以,我正在尝试按照here所述实现一个多变量ZipWithN。不幸的是,Paczesiowa的代码似乎是用ghc和HList的过时版本编译的,所以在尝试理解它是如何工作的过程中,我也将它移植到两者的最新版本(ghc- 7.8.3和此时的HList-0.3.4.1)。这很有趣。
无论如何,在中间函数curryN'
的定义中,我遇到了谷歌没有帮我修复一次的错误。在概念上,curryN'
很简单:它采用类型级自然数N
(或严格来说,该类型的值),以及函数f
,其第一个参数是长度为N
的HList,并返回一个N
- ary函数,该函数使HList脱离其第一个N
参数,并返回应用于该HList的f
。它是curry
,但是是多变量的。
它使用三个辅助函数/类:
第一个是ResultType
/ resultType
,因为我已定义here。 resultType
将一个函数作为参数,并在将该函数应用于所需的参数之后返回该函数的类型。 (严格地说,它再次返回该类型的未定义值)。
例如:
ghci> :t resultType (++)
resultType (++) :: [a]
ghci> :t resultType negate
resultType negate :: (ResultType a result, Num a) => result
(后一种情况,因为如果a
碰巧是类型x -> y
的函数,则resultType必须返回y
。所以它不适用于多态函数。)
后两个是Eat
/ eat
和MComp
/ mcomp
,在一个文件中一起定义(以及curryN'
)(以及已损坏curryN'
},如this。
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
无法通过eat
的多态返回类型进行递归(即使这是由类型级自然数修复的)。但如果是这样的话,我不知道如何解决这个问题。
另外(对我来说很奇怪),如果我尝试将Part1.hs
和Part2.hs
合并为一个file,我仍会收到错误...但是另一个错误
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
类型变量。我承认我在这里有一点点类型的东西,所以如果有人能帮我弄清楚这里究竟是什么问题,更重要的是,我如何解决它(如果是的话,希望,可能),我将非常感激。
最后注意:这里的两个文件称为Part1和Part3的原因是Part2包含zipWithN
中使用的一些辅助函数,但不包含curryN'
。在大多数情况下,他们的工作正常,但我可能会在稍后讨论一些奇怪的事情。