【问题标题】:How to choose right Haskell C type?如何选择合适的 Haskell C 类型?
【发布时间】:2011-06-22 22:31:17
【问题描述】:

我研究了一些 Haskell 编程语言,现在我发现可以从 C 程序中调用 Haskell 函数。在我学习 Haskell 期间,我用 Haskell 创建了一个词频计数器,我想尝试从 C 程序中调用该函数,但我不知道该怎么做。我在 haskell.org 上找到了这两个网站:

Calling Haskell from C

Foreign C types (Haskell module)

尽管如此,我还是有点不知道要使用哪种类型。我的 haskell 程序是以下功能的管道:

putStr 。取消线。映射 testF 。排序树

我自己的功能在哪里

  • testFtestF :: Show a => ([Char],a) -> [Char] 的类型
  • sortedTreesortedTree :: (Num a, Ord a) => [Char] -> [([Char],a)] 的类型

我很确定我需要将每个函数的类型转换为 C 类型,而不是只转换调用管道的函数。 “main”函数的类型是

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 }

谁能指导我一下?

【问题讨论】:

  • 很酷的问题,不幸的是,这个矩阵上似乎没有人有帮助asset.soup.io/asset/0750/2820_15d5_960.jpeg 我希望它没有冒犯,只是在您等待合理答案时很有趣。 +1 当然
  • 我不清楚。您能否明确说明您希望从 C 调用哪个 Haskell 函数?假设您的绑定正常工作 - 一个简单的 C 调用程序是什么样的?
  • @TomMD:我正在尝试从 C 程序调用 fileFreq 函数。简单的 C 调用程序看起来只是一个简单的 C 程序,其中只有 Haskell 函数调用。

标签: c haskell types ffi


【解决方案1】:

您需要做的是为需要暴露给 C 的函数创建包装函数,并在那里完成从 C 类型转换为 haskell 类型的工作。

您还需要启用 ForeignFunctionInterface 扩展,haskell 代码中可能出现的任何异常都需要在包装函数中处理。

例如,如果您只需要向 C 公开顶级函数 fileFreq,则可以添加如下函数:

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

【讨论】:

  • 我试过你的代码,我可以编译它没有错误。但是至少有两件事我想知道:a)为什么只需要“转换”被调用的 fileFreq 函数? GHC 编译器会自动处理子函数类型吗? b) 我试图理解看起来很奇怪的 _stub.c 源文件,不幸的是我不知道应该如何输入我想要处理的文本文件。 .c文件中fileFreq函数的定义为“HsInt32 fileFreq_hs(HsPtr a1)”。
  • 唯一需要担心类型的地方是要导出到 C 代码的函数。只有在那里,您才需要在 C 类型和 Haskell 类型之间进行转换。子功能类型不需要修改,实际上也不应该修改。 GHC 编译器不会对子函数类型做任何事情,而是显式地转换为 haskell 类型,然后所有其他函数都使用 Haskell 类型。作为 C 用户,您只需要包含生成的头文件,然后使用 GHC 将所有文件与您的 C 文件一起编译(根据您在问题中的链接)。
  • 谢谢。我认为这一切都开始慢慢变得有意义了:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-11
  • 2013-07-19
  • 2020-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-03
相关资源
最近更新 更多