我正在尝试开始使用Haskell的LLVM绑定.一个很好的起点是Hello World.
以下是来自绑定作者的博客.
bldGreet :: CodeGenModule (Function (IO ()))
bldGreet = do
puts <- newNamedFunction ExternalLinkage "puts" :: TFunction (Ptr Word8 -> IO Word32)
greetz <- createStringNul "Hello, World!"
func <- createFunction ExternalLinkage $ do
tmp <- getElementPtr greetz (0::Word32, (0::Word32, ()))
call puts tmp -- Throw away return value.
ret ()
return func
Run Code Online (Sandbox Code Playgroud)
它不编译.
相反,我得到"模糊类型变量n0' in the constraint:
(type-level-0.2.4:Data.TypeLevel.Num.Sets.NatI n0)
arising from a use ofgetElementPtr0'可能修复:添加修复这些类型变量的类型签名"
这是一个可行的变体
llvmModule :: TFunction (IO Word32)
llvmModule =
withStringNul "Hello world!" $ \s -> do
puts <- newNamedFunction ExternalLinkage "puts" :: TFunction (Ptr Word8 -> IO Word32)
main <- newNamedFunction ExternalLinkage "main" :: TFunction (IO Word32)
defineFunction main $ do
tmp <- getElementPtr0 s (0::Word32, ())
_ <- call puts tmp
ret (0::Word32)
return main
Run Code Online (Sandbox Code Playgroud)
第一个似乎更自然.我的问题是第一个是什么模糊,我该如何解决它.我的第二个问题是为什么第二个问题不明确.
好的。所以我解决了这个问题。这确实是一个类型类的东西。这只会让我更加困惑。不过,我确实有解决方案的答案。但请随时帮助我理解。首先,进行一些挖掘。函数 createStringNul 具有类型
createString :: String -> TGlobal (Array n Word8)
Run Code Online (Sandbox Code Playgroud)
美好的。编译器遇到的问题是数组类型中的“n”不明确。它实际上可以是世界上的任何东西。查找、数组,然后你就看到了
newtype Array n a
Run Code Online (Sandbox Code Playgroud)
现在不是那么明显了,但是经过一点挖掘,特别是对 getElementPtr 的调用,我们发现 n 实际上应该是 Nat n,这是一种固定数组大小的类型级方法。现在,数组 na 的定义实际上并不关心它实际上只是 [a] 的类型同义词。因此,您可以使用 D0、D9 或 Data.TypeLevel.Num.Reps 包中您想要的任何内容。固定数组的大小,虽然这个函数实际上没有考虑到一个好主意。但无论如何,改变greetz <- createStringNul“Hello, World!” 问候 <- createStringNul "你好,世界!" :: TGlobal(数组 D0 Word8)有效。
这是有趣的部分......我没想到它会起作用。D0 应该是 0,所以我不明白为什么它允许我在 0 大小的“数组”中存储这么多字符但是,如果你查看源代码,你会立即清楚类型限制实际上并不存在关注了。
好吧,无论如何,在编译后,人们意识到 createStringNul 已被弃用,而 withStringNul 是首选。但我不完全理解 withStringNul 的类型是如何工作的。