Haskell LLVM绑定模糊类型

时间:2013-04-12 18:14:10

标签: haskell llvm ffi

我正在尝试开始使用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

第一个似乎更自然。我的问题是第一个含糊不清,我该如何解决它。我的第二个问题是为什么第二个问题不明确。

2 个答案:

答案 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。