2010-03-18 14 views
63
data GroceryItem = CartItem ItemName Price Quantity | StockItem ItemName Price Quantity 

makeGroceryItem :: String -> Float -> Int -> GroceryItem 
makeGroceryItem name price quantity = CartItem name price quantity 

I want to create a `GroceryItem` when using a `String` or `[String]` 

createGroceryItem :: [String] -> GroceryItem 
createGroceryItem (a:b:c) = makeGroceryItem a b c 

इनपुट ["Apple","15.00","5"] प्रारूप में होगा जो मैंने हास्केल के words फ़ंक्शन का उपयोग करके तोड़ दिया।हास्केल में स्ट्रिंग को इंटीजर/फ्लोट में कनवर्ट करें?

मुझे निम्न त्रुटि मिलती है जो मुझे लगता है क्योंकि makeGroceryItemFloat और Int स्वीकार करता है।

*Type error in application 
*** Expression  : makeGroceryItem a read b read c 
*** Term   : makeGroceryItem 
*** Type   : String -> Float -> Int -> GroceryItem 
*** Does not match : a -> b -> c -> d -> e -> f* 

लेकिन मैं कैसे कर सकता हूँ b और प्रकार Float की c और Int क्रमश?

+0

आपके पास एक दिलचस्प परियोजना है। ये किसके लिये है? –

उत्तर

80

read नाव में एक स्ट्रिंग पार्स और int कर सकते हैं:

Prelude> :set +t 
Prelude> read "123.456" :: Float 
123.456 
it :: Float 
Prelude> read "123456" :: Int 
123456 
it :: Int 

लेकिन समस्या यह है (1) अपने पैटर्न में है:

createGroceryItem (a:b:c) = ... 

यहाँ : एक (राइट-साहचर्य) द्विआधारी ऑपरेटर है जो एक सूची में एक तत्व तैयार करता है। तत्व का आरएचएस एक सूची होना चाहिए। इसलिए, अभिव्यक्ति a:b:c दिया, हास्केल निम्नलिखित प्रकार यह निष्कर्ष निकाल देगा:

a :: String 
b :: String 
c :: [String] 

अर्थात c स्ट्रिंग की एक सूची के रूप में सोचा की जाएगी। जाहिर है यह read नहीं हो सकता है या स्ट्रिंग की अपेक्षा रखने वाले किसी भी कार्य में पारित नहीं हो सकता है।

इसके बजाय आप

createGroceryItem [a, b, c] = ... 

का उपयोग करता है, तो सूची वास्तव में 3 आइटम, या

createGroceryItem (a:b:c:xs) = ... 

होना आवश्यक है यदि ≥3 आइटम स्वीकार्य है चाहिए।

इसके अलावा

(2), अभिव्यक्ति

makeGroceryItem a read b read c 

रूप makeGroceryItem 5 तर्क, जिनमें से 2 read समारोह कर रहे हैं लेने में व्याख्या की जाएगी।

makeGroceryItem a (read b) (read c) 
+0

@ केनीटीएम: 'पढ़ें "123.456" :: फ्लोट'। इस वाक्यविन्यास का क्या अर्थ है? यहां '::' क्या है? क्या एक समारोह पढ़ा जाता है? – Nawaz

+0

@ नवाज: हां 'पढ़ा' एक समारोह है। 'F :: टी' अभिव्यक्ति बल 'f' टाइप करने के लिए' टी' है। – kennytm

+0

@ केनीटीएम: तो सिंटैक्स 'पढ़ा गया "123.456" :: फ्लोट' लगभग एसएसकेएनएफ ("123.456", "% f", &fnum); 'सी में बराबर है, दाएं? – Nawaz

5

दो बातें::

createGroceryItem [a, b, c] = makeGroceryItem a (parse b) (parse c) 
-- pattern match error if not exactly 3 items in list 

या वैकल्पिक रूप से

createGroceryItem (a : b : c : _) = makeGroceryItem a (parse b) (parse c) 
-- pattern match error if fewer than 3 items in list, ignore excess items 

क्योंकि :++ के समान नहीं है आप कोष्ठकों का प्रयोग करने की जरूरत है।

इस बीच दायीं तरफ --- वह पक्ष जो आपको त्रुटि संदेश दे रहा है --- आपको ब्रैकेट का उपयोग करके अभिव्यक्तियों को समूहबद्ध करना होगा। अन्यथा parse को उस मान के रूप में व्याख्या किया गया है जिसे आप makeGroceryItem पर पास करना चाहते हैं, इसलिए संकलक शिकायत करता है जब आप उस फ़ंक्शन में 5 तर्क पारित करने का प्रयास करते हैं जो केवल 3 पैरामीटर लेता है।

75

भले ही इस प्रश्न का उत्तर पहले से ही है, मैं दृढ़ता से स्ट्रिंग रूपांतरण के लिए reads का उपयोग करने का सुझाव देता हूं, क्योंकि यह अधिक सुरक्षित है, क्योंकि यह एक अप्राप्य अपवाद के साथ विफल नहीं होता है।

reads :: (Read a) => String -> [(a, String)] 

Prelude> reads "5" :: [(Double, String)] 
[(5.0,"")] 
Prelude> reads "5ds" :: [(Double, String)] 
[(5.0,"ds")] 
Prelude> reads "dffd" :: [(Double, String)] 
[] 

सफलता पर, reads ठीक एक तत्व के साथ एक सूची देता है: एक टपल है और रूपांतरित मूल्य से मिलकर शायद unconvertable अतिरिक्त वर्ण। विफलता पर, reads एक खाली सूची देता है।

सफलता और विफलता पर पैटर्न-मिलान करना आसान है, और यह आपके चेहरे पर उड़ नहीं जाएगा!

+1

महान सुझाव! परिणामी आइटम को पढ़ने से लौटाई गई सूची से निकालने का आपका पसंदीदा तरीका क्या है? दो 'एफटीटी' कॉल? –

+7

आधार-4.6 के बाद, ['readMaybe :: पढ़ें => स्ट्रिंग -> शायद ए'] (http://hackage.haskell.org/package/base-4.9.0.0/docs/Text-Read.html #v: readMaybe) 'Text.Read' में, जो इस मामले में' reads' का उपयोग करने से अधिक सुविधाजनक है। – sjakobi

0
filterNumberFromString :: String -> String 
filterNumberFromString s = 
    let allowedString = ['0'..'9'] ++ ['.', ','] 
     toPoint n 
      | n == ',' = '.' 
      | otherwise = n 

     f = filter (`elem` allowedString) s 
     d = map toPoint f 
    in d 


convertStringToFloat :: String -> Float 
convertStringToFloat s = 
    let betterString = filterNumberFromString s 
     asFloat = read betterString :: Float 
    in asFloat 

print (convertStringToFloat "15,00" + 1) 

-> प्रिंट 16.0

Thats कैसे मैं अपने प्रोजेक्ट में इस कार्य को हल किया।

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