6

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 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

最初のほうがより自然に見えます。私が持っている質問は、最初のあいまいさとは何か、それをどのように修正するかです。私が持っている2番目の質問は、なぜ2番目があいまいではないのかということです.

4

2 に答える 2

1

わかった。だから私は問題を解決しました。それは確かに型クラスのものです。そして、それは私をさらに混乱させただけです。しかし、私は解決策への答えを持っています。しかし、私の理解を助けてください。まずは掘り出し物。関数 createStringNul には型があります

createString :: String -> TGlobal (Array n Word8)

罰金。コンパイラが抱えていた問題は、Array 型の "n" があいまいであることです。それは文字通り世界の何でもあり得ます。ルックアップ、配列、そしてあなたが見る

newtype Array n a

今はそれほど明白ではありませんが、少し掘り下げると、特に getElementPtr の呼び出しに関して、n は実際には Nat n であることがわかります。これは、配列のサイズを修正する型レベルの方法です。ここで、Array na の定義は、実際には [a] の単なる型シノニムであることを気にしません。したがって、D0、D9、または Data.TypeLevel.Num.Reps パッケージから必要なものを使用できます。配列のサイズを修正しましたが、この関数では実際には考慮されていませんでした。とにかく、greetz <- createStringNul "Hello, World!" を変更します。to greetingz <- createStringNul "Hello, World!" :: TGlobal (配列 D0 Word8) は機能します。

ここが興味深い部分です...うまくいくとは思っていませんでした。D0 は 0 のはずなので、なぜ 0 のサイズの「配列」にこれほど多くの文字を格納できるようになっているのかわかりませんでしたが、ソース コードを見れば、実際には型の制限がないことがすぐにわかります。に注目した。

とにかく、コンパイルすると、createStringNul が推奨されなくなり、代わりに withStringNul が優先されることがわかります。withStringNul の型がどのように機能するかを完全には理解していないことを除いて。

于 2013-04-13T19:02:48.150 に答える
1

createStringNul llvm(3.0.1.0)の現在のバージョンでは非推奨としてマークされています。使用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を持っています。これは、 が自然数であるすべての関数が機能することを意味します。nn

本当に を使用したい場合は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

:*型コンストラクターは型レベル パッケージに由来し、型レベルの数値を構築するために使用されます。D1 :* D3は、配列のサイズが 13 であることを意味します。

于 2013-04-13T19:05:20.563 に答える