wake-up-neo.com

Konvertieren Sie String in Integer/Float in Haskell?

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

Die Eingabe erfolgt in dem Format ["Apple","15.00","5"], das ich mit der Haskell-Funktion words getrennt habe.

Ich erhalte die folgende Fehlermeldung, die ich denke, weil makeGroceryItem eine Float und eine Int akzeptiert.

*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*

Aber wie mache ich b und c vom Typ Float bzw. Int?

67
Ranhiru Cooray

read kann einen String in float und int parsen:

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

Aber das Problem (1) liegt in Ihrem Muster:

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

Hier ist : ein (rechtsassoziativer) Binäroperator, der ein Element einer Liste voranstellt. Die RHS eines Elements muss eine Liste sein. Daher wird Haskell mit dem Ausdruck a:b:c die folgenden Typen ableiten:

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

c wird als Liste von Strings gedacht. Natürlich kann es nicht read sein oder an Funktionen übergeben werden, die einen String erwarten.

Stattdessen sollten Sie verwenden

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

wenn die Liste genau 3 Elemente enthalten muss, oder 

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

wenn ≥3 Artikel akzeptabel sind.

Auch (2) der Ausdruck

makeGroceryItem a read b read c

wird als makeGroceryItem interpretiert, wobei 5 Argumente verwendet werden, von denen 2 die read-Funktion sind. Sie müssen Klammern verwenden:

makeGroceryItem a (read b) (read c)
84
kennytm

Auch wenn diese Frage bereits beantwortet wurde, empfehle ich dringend, reads für die Konvertierung von Strings zu verwenden, da sie viel sicherer ist, da sie nicht mit einer nicht behebbaren Ausnahme fehlschlägt.

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)]
[]

Bei Erfolg gibt reads eine Liste mit genau einem Element zurück: Ein Tuple, das aus dem konvertierten Wert und möglicherweise nicht konvertierbaren zusätzlichen Zeichen besteht. Bei einem Fehler gibt reads eine leere Liste zurück.

Es ist einfach, bei Erfolg und Misserfolg ein Pattern-Match zu erstellen, und es wird Ihnen nicht ins Gesicht springen!

76
LukeN

Zwei Dinge:

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

oder alternativ

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

weil : nicht gleich ++ ist.

In der Zwischenzeit auf der rechten Seite - der Seite, die Ihnen die Fehlermeldung anzeigt - müssen Sie die Ausdrücke mit Klammern gruppieren. Andernfalls wird parse als Wert interpretiert, den Sie an makeGroceryItem übergeben möchten. Der Compiler beschwert sich also, wenn Sie versuchen, 5 Argumente an eine Funktion zu übergeben, die nur 3 Parameter benötigt.

5
dave4420
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)

-> druckt 16.0

So habe ich diese Aufgabe in meinem Projekt gelöst.

0
chrisheyn