我正在尝试解决使用Haskell llvm绑定时发生的编译时错误。
代码:
-- Line 14 follows
type Acc = Int32 -> Int32 -> IO Int32
type Sig = Int32 -> Ptr Int32 -> Function Acc-> IO Int32
-- [...]
-- Line 31 follows
mSum :: CodeGenModule (Function Sig)
mSum = createNamedFunction ExternalLinkage "sum" $ \l ptr_x fn -> do
r <- forLoop (valueOf 0) l (valueOf (0::Int32)) $ \i sum -> do
xi <- getIndex ptr_x i
x <- load xi
call fn sum x
ret r
Comentary :mSum
是一个monadic函数,它为llvm函数生成一个咬合代码。生成的函数用于获取三个参数:l
:整数数组的长度; ptr_x
指向整数数组的指针;和fn
一个函数。 (第32行)生成的函数将使用名为sum
的累加器循环遍历数组的元素。对于每个值,x
,sum
和x
将传递给函数fn
。该函数的结果将在下一次循环时变为sum
的值。 sum的最终值将作为生成函数的值返回。
错误:
llvm3.hs:32:8:
Context reduction stack overflow; size = 21
Use -fcontext-stack=N to increase stack size to N
$dFunctionArgs :: FunctionArgs
(Function Acc -> b17)
(Value (Ptr (Int32 -> Int32 -> IO Int32)) -> b'17)
r18
$dFunctionArgs :: FunctionArgs
(Ptr (Int32 -> Int32 -> IO Int32) -> b16)
(Value (Function Acc) -> b'16)
r17
-- [ ... ]
$dFunctionArgs :: FunctionArgs
(Ptr (Int32 -> Int32 -> IO Int32) -> b4)
(Value (Function Acc) -> b'4)
r5
$dFunctionArgs :: FunctionArgs
(Function Acc -> b3)
(Value (Ptr (Int32 -> Int32 -> IO Int32)) -> b'3)
r4
$dFunctionArgs :: FunctionArgs
(Ptr (Int32 -> Int32 -> IO Int32) -> b2)
(Value (Function Acc) -> b'2)
r3
$dFunctionArgs :: FunctionArgs
(Function Acc -> IO Int32)
(Function (Int32 -> Int32 -> IO Int32)
-> CodeGenFunction r Terminate)
(CodeGenFunction r0 ())
$dFunctionArgs :: FunctionArgs
(Ptr a0 -> b1) (Value (Ptr Int32) -> b'1) r2
$dFunctionArgs :: FunctionArgs
(Ptr Int32 -> Function Acc -> IO Int32)
(Value (Ptr a0)
-> Function (Int32 -> a0 -> IO Int32)
-> CodeGenFunction r Terminate)
(CodeGenFunction r0 ())
$dFunctionArgs :: FunctionArgs (i0 -> b) (Value Int32 -> b') r1
$dFunctionArgs :: FunctionArgs
Sig
(Value i0
-> Value (Ptr a0)
-> Function f0
-> CodeGenFunction r19 Terminate)
(CodeGenFunction r0 ())
In the expression: createNamedFunction ExternalLinkage "sum"
In the expression:
createNamedFunction ExternalLinkage "sum"
$ \ l ptr_x fn
-> do { r <- forLoop (valueOf 0) l (valueOf (0 :: Int32))
$ \ i sum -> ...;
ret r }
In an equation for `mSum':
mSum
= createNamedFunction ExternalLinkage "sum"
$ \ l ptr_x fn
-> do { r <- forLoop (valueOf 0) l (valueOf (0 :: Int32)) $ ...;
.... }
问题:有两个可能的问题:如果我没有正确传递函数,那么如何将指针传递给LLVM中的函数?否则我需要做什么来满足类型检查器?
除了:我不太了解Haskell的工作,足以理解我为什么会遇到这个错误。我也不理解createNamedFunction
上的类型签名:
(IsFunction f, FunctionArgs f g (CodeGenFunction r ()))
=> Linkage
-> String
-> g -- Function body.
-> CodeGenModule (Function f)
答案 0 :(得分:9)
哦,好悲伤。
是的,您可能遇到某种类型错误。这里的库使用UndecidableInstances
来做一些花哨的类型级逻辑,其中“花哨”意味着“如果你运气不好就会导致类型检查器进入无限循环”。你可能猜到你现在有多幸运。不幸的是,虽然由此产生的令人震惊的错误告诉我们哪里正在发生循环,但它并不像人们想要的那样提供信息为什么。
另外,请注意,不理解为什么会出现此错误是完全合理的。这是混乱和混乱。接下来是一些粗略的解释和我对缩小原因的想法:
首先,在计算FunctionArgs
时,循环显然正在发生。考虑类的定义:
class FunctionArgs f g r | f -> g r, g r -> f where
...
|
之后的部分是功能依赖,指定某些参数唯一地确定其他参数。在这种情况下,f
以及g
和r
的组合相互决定,因此它是一种可以在任一方向上计算的双向函数。
您的功能为mSum :: CodeGenModule (Function Sig)
,使用createNamedFunction
的签名统一,Sig
作为f
参数,r
和g
目前未知。类型同义词Sig
会扩展为Int32 -> Ptr Int32 -> Function Acc-> IO Int32
。现在,我们可以查看FunctionArgs
的{{3}},看看这给了我们什么。
运算符优先级为最左边的函数箭头提供Sig
的最外层类型构造函数,因此我们找到匹配的实例:FunctionArgs b b' r => FunctionArgs (a -> b) (Value a -> b') r
。我们可以替换类型,根据需要进行统一,并重复:
FunctionArgs (Ptr Int32 -> Function Acc-> IO Int32) b' r => FunctionArgs (Int32 -> (Ptr Int32 -> Function Acc-> IO Int32)) (Value Int32 -> b') r
FunctionArgs (Function Acc-> IO Int32) b' r => FunctionArgs (Ptr Int32 -> (Function Acc-> IO Int32)) (Value (Ptr Int32) -> b') r
您应该能够在出现的错误中将这些步骤与堆栈跟踪相匹配。一个有趣的事情是,堆栈跟踪中有额外的步骤,我不确定其原因 - 与我基于功能依赖性填充类型的方式有关,我想。看起来它首先基于(->)
类型构造函数选择实例,然后填充Value a -> b
参数的g
类型构造函数,然后执行递归步骤(在上下文中)返回统一其余类型。
现在,我们知道在这一点上出现问题的时候;这可以从堆栈溢出的通用原则推断出来,这就是问题就在堆栈跟踪开始反复重复相同模式之前的某个地方。
对于下一次缩减,f
使用Function Acc-> IO Int32
进行实例化,而g
和r
到目前为止仍未确定(尽管我们知道它们必须由{{唯一确定) 1}})。此时查看f
的定义也是个好主意:Function
type Function a = Value (Ptr a)
同样,我们使用功能箭头选择实例:FunctionArgs (Value (Ptr Acc) -> IO Int32) g r
...这就是可疑的事情,因为如果你比较上面的堆栈跟踪,它会显示FunctionArgs b b' r => FunctionArgs (a -> b) (Value a -> b') r
参数的(Function (...) -> ...)
。鉴于上面g
的定义,技术上匹配,因为我们期望Function
,它是Value
类型同义词的最外层构造函数。不幸的是,我们对Function
参数也有(Function (...) -> ...)
,这是不一致的,因为f
参数应该有一个额外的g
构造函数。
填写错误的结构后,它会继续卡在应该填写其余类型变量的步骤;看起来好像双向功能依赖性导致它来回反复,反复尝试将Value
与a
统一起来。因此,随着类型同义词的扩展,我们得到了这个:
Value a
FunctionArgs (Value (Ptr Acc) -> b) (Value (Ptr Acc) -> b') r
... ad infinitum。
此时我真的不确定会导致这场冲突的原因。我期望的结果是FunctionArgs (Ptr Acc -> b) (Value (Value (Ptr Acc)) -> b') r
的一致实例选择,我无法真正说出为什么它会被卡住。
编辑:等等,我很傻。我最初误读了你的代码 - 很明显从lambda表达式的推断类型得到了错误类型的一部分,我认为它比实际上更具多态性。特别是,参数FunctionArgs (Value (Ptr Acc) -> b) (Value (Value (Ptr Acc)) -> b') r
作为函数fn
的参数给出,这就是上面创建的不一致类型。我仍然不知道它为什么会进入无限循环,但至少可以解释冲突。
假设由于call :: CallArgs f g => Function f -> g
导致的推断类型正确,call
参数的类型应为g
,这意味着Value Int32 -> Value (Ptr Int32) -> Function Acc-> CodeGenFunction Int32 ()
应为f
},而不是您的类型Int32 -> Ptr Int32 -> Ptr Acc-> IO Int32
。
支持这一点,如果你看一下同样适用于Sig
的{{1}}类,它希望函数参数是原始类型,如IsFunction
或{{1} } s到原始类型,但不是f
,这是Int32
扩展到的。
毕竟,我认为您的问题只是您的类型Ptr
稍有不妥。
...韦尔普。那好吧。