Как правильно выбрать тип Haskell C? - PullRequest
10 голосов
/ 07 февраля 2011

Я изучил некоторый язык программирования Haskell, и теперь я обнаружил, что можно вызывать функции Haskell из программ на Си. Во время обучения на Haskell я создал счетчик частоты слов в Haskell, и я хотел бы попытаться вызвать эту функцию из программы на C, но я не знаю, как это сделать. Я нашел эти два сайта на haskell.org:

Вызов Хаскеля из C

Иностранные типы C (модуль Haskell)

Несмотря на это, я немного потерял, какие типы использовать. Мои программы на haskell - это конвейер следующих функций:

putStr. нелинейные карта testF. sortedTree

где мои собственные функции

  • testF - это тип testF :: Show a => ([Char], a) -> [Char]
  • sortedTree это тип sortedTree :: (Num a, Ord a) => [Char] -> [([Char], a)]

Я совершенно уверен, что мне нужно конвертировать типы каждой функции в типы C, а не просто функцию, которая вызывает конвейер. Тип "основной" функции:

fileFreq :: [Char] -> 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 }

Кто-нибудь может мне немного помочь с этим?

1 Ответ

7 голосов
/ 08 февраля 2011

Вам нужно будет создать функции-обертки для функций, которые вам нужны для работы с 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-заглушку и заголовочный файл и создать C-файл, который выможет компилироваться с ghc.

Конечно, можно обернуть любую функцию, которая у вас есть, вам просто нужно убедиться, что вы обрабатываете возможные исключения и маршалировать между типами 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
...