我正在尝试开始使用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
不编译。
相反,我得到“不明确的类型变量n0' in the constraint:
(type-level-0.2.4:Data.TypeLevel.Num.Sets.NatI n0)
arising from a use of
getElementPtr0”
可能的修复:添加修复这些类型变量的类型签名“
这是一个可行的变体
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
第一个似乎更自然。我的问题是第一个含糊不清,我该如何解决它。我的第二个问题是为什么第二个问题不明确。
答案 0 :(得分:1)
好。所以我解决了这个问题。这确实是一个类型的东西。它只会让我更加困惑。但是,我确实得到了解决方案的答案。但请随时帮助我理解。首先,一些挖掘。函数createStringNul的类型为
createString :: String -> TGlobal (Array n Word8)
精细。编译器遇到的问题是Array类型中的“n”是不明确的。它几乎可以成为世界上的任何东西。查找,数组,你看到了
newtype Array n a
现在它不是那么明显,但是稍微挖掘一下,特别是对getElementPtr的调用,人们发现n,真的应该是一个Nat n,这是一种类型级的方法来修复大小阵列。现在,Array n a的定义实际上并不关心它实际上只是[a]的类型同义词。所以你可以使用D0,或D9或任何你想要的 Data.TypeLevel.Num.Reps 包。修复数组的大小,而这个函数实际上没有考虑好主意。但无论如何,改变 greetz&lt; - createStringNul“Hello,World!” 至 greetz&lt; - createStringNul“Hello,World!” :: TGlobal(阵列D0 Word8) 的工作原理。
这是有趣的部分......我没想到它会起作用。 D0应该是0,所以我不明白为什么它允许我在0大小的“数组”中存储这么多字符但是,如果你看一下源代码,很明显类型限制实际上不是注意。
很好,无论如何,在编译之后意识到不推荐使用createStringNul,而是首选withStringNul。除了我不完全理解withStringNul的类型如何工作。
答案 1 :(得分:1)
createStringNul
(3.0.1.0)中的 llvm
is marked as deprecated。使用withStringNul
:
import Data.Word
import LLVM.Core
bldGreet :: CodeGenModule (Function (IO ()))
bldGreet = do
puts <- newNamedFunction ExternalLinkage "puts" :: TFunction (Ptr Word8 -> IO Word32)
func <- withStringNul "Hello, World!" $ \greetz ->
createFunction ExternalLinkage $ do
tmp <- getElementPtr greetz (0::Word32, (0::Word32, ()))
_ <- call puts tmp -- Throw away return value.
ret ()
return func
至于导致第一个例子中的错误的原因,它与withStringNul
具有更多信息类型的事实有关:withStringNul :: String -> (forall n . Nat n => Global (Array n Word8) -> a) -> a
- cf.到createStringNul :: String -> TGlobal (Array n Word8)
。 withStringNul
的函数参数有一个higher-rank type - 这意味着该函数适用于所有n
n
是自然数。
如果您真的想使用createStringNul
,可以通过为greetz
添加显式类型签名来进行第一个示例编译:
{-# LANGUAGE TypeOperators #-}
module Test
where
import Data.Word
import Data.TypeLevel.Num.Reps
import LLVM.Core
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 :: Global (Array (D1 :* D3) Word8)) (0::Word32, (0::Word32, ()))
call puts tmp -- Throw away return value.
ret ()
return func
:*
类型构造函数comes from the type-level package,用于构造类型级别的数字。 D1 :* D3
表示数组的大小为13。