2011-02-07 10 views
10

मैंने कुछ हास्केल प्रोग्रामिंग भाषा का अध्ययन किया है और अब मुझे पता चला है कि सी प्रोग्राम से हास्केल फ़ंक्शंस को कॉल करना संभव है। मेरे हास्केल अध्ययनों के दौरान, मैंने हास्केल के साथ एक शब्द आवृत्ति काउंटर बनाया और मैं उस समारोह को सी प्रोग्राम से कॉल करने का प्रयास करना चाहता हूं, लेकिन मुझे नहीं पता कि यह कैसे करना है। मैं haskell.org पर इन दोनों वेबसाइटों पाया:सही हास्केल सी प्रकार का चयन कैसे करें?

Calling Haskell from C

Foreign C types (Haskell module)

उस के बावजूद, मैं थोड़ा जो प्रकार का उपयोग करने खो रहा हूँ। मेरे हैकेल प्रोग्राम निम्नलिखित कार्यों का एक पाइपलाइन है:

putStr। अनलॉक मानचित्र परीक्षण एफ। sortedTree

जहां मेरे अपने कार्यों

  • testF है की testF :: शो में एक => प्रकार ([चार], एक) -> [चार]
  • sortedTreeक्रमबद्ध ट्री :: (संख्या ए, ऑर्ड ए) => [चार] -> [([चार], ए)]

मुझे पूरा यकीन है कि मुझे प्रत्येक फ़ंक्शन के प्रकारों को सी प्रकारों में परिवर्तित करने की आवश्यकता है, केवल पाइपलाइन को कॉल करने वाले फ़ंक्शन को बदलने के बजाय। "मुख्य" समारोह के प्रकार

fileFreq है :: [चार] -> आईओ()

यह सब इसके अलावा, मैं एक 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 } 

किसी को भी इस के साथ मुझे थोड़ी मार्गदर्शन कर सकते हैं:

यहाँ पूरे हास्केल कोड है?

+5

कूल सवाल है, दुर्भाग्य से इस मैट्रिक्स पर कोई भी उपयोगी http://asset.soup.io/asset/0750/2820_15d5_960.jpeg होने के लिए मैं यह आशा है कि लगता है आप उचित जवाब की प्रतीक्षा करते समय अपमानजनक नहीं हैं। पाठ्यक्रम का +1 – stacker

+0

यह मेरे लिए अस्पष्ट नहीं है। क्या आप स्पष्ट हो सकते हैं कि आप किस हास्केल फ़ंक्शन को सी से कॉल करना चाहते हैं? दिखाओ कि आपके पास बाइंडिंग काम कर रही है - एक सरल सी कॉलर कैसा दिखता है? –

+1

@ स्टैकर: अनमोल: डी – Skurmedel

उत्तर

7

आपको सी के संपर्क में आने वाले कार्यों के लिए रैपर फ़ंक्शंस बनाने की आवश्यकता होगी और सी-प्रकारों से हैकेल प्रकारों में कनवर्ट करने का कार्य करें।

आपको विदेशी फ़ंक्शन इंटरफेस एक्सटेंशन को भी सक्षम करने की आवश्यकता होगी, हैकल कोड में होने वाले किसी भी अपवाद को रैपर फ़ंक्शंस में संभालने की आवश्यकता है।

उदाहरण के लिए, आप की तरह एक समारोह जोड़ सकता है अगर आप केवल सेल्सियस के लिए अपने उच्च-स्तरीय समारोह 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 

एक समारोह है कि एक haskell स्ट्रिंग में एक सी स्ट्रिंग मार्शलों बनाने के लिए (Foreign.C.String से फ़ंक्शंस का उपयोग करके), आपकी फ़ाइल फ़्रेक फ़ंक्शन को कॉल करता है और सी त्रुटि कोड में अपवाद का अनुवाद करता है (-1 अगर अपवाद हुआ, 0 अन्यथा)।

तो फिर तुम

foreign export ccall fileFreq_hs :: CString -> IO CInt 

उपयोग करके उसका निर्यात करने की जरूरत है और निश्चित रूप से आप जोड़ने की जरूरत:

{-# LANGUAGE ForeignFunctionInterface #-} 

अपने मॉड्यूल के शीर्ष पर।

फिर आप सी-स्टब और हेडर फ़ाइल में संकलित करने के लिए दिए गए लिंक में दिए गए निर्देशों का पालन कर सकते हैं और एक सी-फाइल बना सकते हैं जिसे आप ghc के साथ संकलित कर सकते हैं।

आपके पास किसी भी फ़ंक्शन को लपेटना संभव है, आपको केवल संभावित अपवादों को संभालने और सी-प्रकारों और हैकेल प्रकारों के बीच मार्शल को सुनिश्चित करने की आवश्यकता है।

पूरा कोड मेरी संशोधनों के साथ है:

{-# 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 
+0

महान उत्तर के लिए धन्यवाद। – zaplec

+1

मैंने आपके कोड की कोशिश की और मैं इसे बिना किसी त्रुटि के संकलित कर सकता हूं। हालांकि कम से कम दो चीजें हैं जो मैं सोच रहा हूं: ए) क्यों केवल फ़ाइल फ़्रेक फ़ंक्शन को "रूपांतरित" करने की आवश्यकता है? क्या जीएचसी कंपाइलर स्वचालित रूप से सबफंक्शन प्रकारों को संभालता है? बी) मैंने बहुत अजीब लग रही _stub.c स्रोत फ़ाइल को समझने की कोशिश की और दुर्भाग्य से मुझे नहीं पता कि मुझे उस टेक्स्ट फ़ाइल को कैसे इनपुट करना चाहिए जिसे मैं संसाधित करना चाहता हूं। .c फ़ाइल में फ़ाइल फ़्रेक फ़ंक्शन का निश्चित विवरण "HsInt32 फ़ाइल Freq_hs (HsPtr a1)" है। – zaplec

+1

एकमात्र ऐसा स्थान जहां आपको प्रकारों के बारे में चिंता करने की आवश्यकता है वह वह कार्य है जिसे आप सी-कोड में निर्यात करना चाहते हैं। वहां और केवल वहां आपको सी-प्रकार और हास्केल प्रकारों के बीच कनवर्ट करने की आवश्यकता है। उपखंड प्रकार को संशोधित करने की आवश्यकता नहीं है, और वास्तव में संशोधित नहीं किया जाना चाहिए। जीएचसी कंपाइलर सबफंक्शन प्रकारों के बारे में कुछ भी नहीं करेगा, बल्कि आप स्पष्ट रूप से हैकेल प्रकारों में कनवर्ट करते हैं, फिर अन्य सभी फ़ंक्शन हास्केल प्रकारों का उपयोग करते हैं। सी-यूजर के रूप में आपको केवल जेनरेट की गई हेडर फ़ाइल को शामिल करने की आवश्यकता है, और उसके बाद जीएचसी (आपके प्रश्न में मौजूद लिंक के अनुसार) के माध्यम से सभी फाइलों को अपनी सी फाइल के साथ संकलित करें। – dnaq

संबंधित मुद्दे