10

私はいくつかの Haskell プログラミング言語を勉強しましたが、C プログラムから Haskell 関数を呼び出すことができることを知りました。Haskell の研究中に、Haskell で単語頻度カウンターを作成しました。その関数を C プログラムから呼び出したいのですが、その方法がわかりません。haskell.org で次の 2 つの Web サイトを見つけました。

C から Haskell を呼び出す

外部 C タイプ (Haskell モジュール)

それにもかかわらず、どのタイプを使用するか少し迷っています。私の haskell プログラムは、次の関数のパイプラインです。

putStr 。線を外します。マップ testF 。並べ替えられたツリー

自分が機能する場所

  • testFは testF の型です:: Show a => ([Char],a) -> [Char]
  • sortedTreeは sortedTree の型です:: (Num a, Ord a) => [Char] -> [([Char],a)]

パイプラインを呼び出す関数だけを変換するのではなく、各関数の型を C 型に変換する必要があることは確かです。「メイン」関数のタイプは

fileFreq :: [文字] -> IO ()

これらすべてに加えて、プレリュード タイプではない Haskell バイナリ ツリーを使用しています。

Haskell コード全体は次のとおりです。

module WordCounter where

import List
import Char
import Foreign.C.Types

data BTree a = Tip | BNode a (BTree a) (BTree a) deriving Show

insertFreq x Tip = BNode (x,1) Tip Tip
insertFreq x (BNode (q,p) l r)  | (map toLower x)==(map toLower q)  = BNode (q, p+1) l r
                | otherwise                 = BNode (q,p) l (insertFreq x r)

tlist :: BTree a -> [a]
tlist Tip = []
tlist (BNode x l r) = concat [tlist l, [x], tlist r]

sortedTree x = sortBy (\(x,y) (p,q) -> compare q y) (tlist (foldr insertFreq Tip (words x)))

testF (x, n) = concat (x : ":" : " \t\t\t " : show n : [])

concord = putStr . unlines . map testF . sortedTree

fileFreq filename = do { text <- readFile filename; concord text }

誰でもこれで私を少し案内できますか?

4

1 に答える 1

7

あなたがする必要があるのは、Cに公開する必要のある関数のラッパー関数を作成することであり、そこでCタイプからhaskellタイプに変換する作業を行います。

また、ForeignFunctionInterface拡張機能を有効にする必要があります。また、haskellコードで発生する可能性のある例外は、ラッパー関数で処理する必要があります。

たとえば、最上位の関数fileFreqをCに公開するだけでよい場合は、次のような関数を追加できます。

fileFreq_hs :: CString -> IO CInt
fileFreq_hs cstr = catch (wrap_fileFreq cstr) (\_ -> return (-1))
  where wrap_fileFreq = do
          str <- peekCString cstr
          fileFreq str
          return 0

C文字列をhaskell文字列にマーシャリングする関数を作成するには(Foreign.C.Stringの関数を使用)、fileFreq関数を呼び出し、例外をCエラーコードに変換します(例外が発生した場合は-1、それ以外の場合は0)。

次に、を使用してエクスポートする必要があります

foreign export ccall fileFreq_hs :: CString -> IO CInt

そしてもちろん、あなたは追加する必要があります:

{-# LANGUAGE ForeignFunctionInterface #-}

モジュールの上部にあります。

次に、提供したリンクの指示に従って、これをCスタブとヘッダーファイルにコンパイルし、ghcでコンパイルできるCファイルを作成できます。

もちろん、持っている関数をラップすることは可能です。可能な例外を処理し、Cタイプとhaskellタイプの間でマーシャリングする必要があります。

私が変更した完全なコードは次のとおりです。

{-# LANGUAGE ForeignFunctionInterface #-}
module WordCounter where

import List
import Char
import Foreign.C.Types
import Foreign.C.String
import Control.Monad

data BTree a = Tip | BNode a (BTree a) (BTree a) deriving Show

insertFreq x Tip = BNode (x,1) Tip Tip
insertFreq x (BNode (q,p) l r)  | (map toLower x)==(map toLower q)  = BNode (q, p+1) l r
                | otherwise                 = BNode (q,p) l (insertFreq x r)

tlist :: BTree a -> [a]
tlist Tip = []
tlist (BNode x l r) = concat [tlist l, [x], tlist r]

sortedTree :: (Ord t, Num t) => String -> [([Char], t)]
sortedTree x = sortBy (\(x,y) (p,q) -> compare q y) (tlist (foldr insertFreq Tip (words x)))

testF :: (Show t) => ([Char], t) -> [Char]
testF (x, n) = concat (x : ":" : " \t\t\t " : show n : [])

concord = putStr . unlines . map testF . sortedTree

fileFreq filename = do { text <- readFile filename; concord text }

fileFreq_hs :: CString -> IO CInt
fileFreq_hs cstr = catch (wrap_fileFreq cstr) (\_ -> return (-1))
  where wrap_fileFreq cstr = do
          str <- peekCString cstr
          fileFreq str
          return 0
foreign export ccall fileFreq_hs :: CString -> IO CInt
于 2011-02-08T09:57:59.250 に答える