IT박스

Haskell에서 문자열을 정수 / 부동으로 변환 하시겠습니까?

itboxs 2020. 11. 7. 09:08
반응형

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

입력은 ["Apple","15.00","5"]Haskell의 words기능을 사용하여 분리 한 형식 입니다 .

나는 때문에 생각 다음과 같은 오류 얻을 makeGroceryItem수용 Float과를 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*

하지만 어떻게해야합니까 bc유형 FloatInt각각?


read 문자열을 float 및 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) = ...

다음 :은 목록에 요소를 추가하는 (오른쪽 연관) 이항 연산자입니다. 요소의 RHS는 목록이어야합니다. 따라서 표현식이 주어지면 a:b:cHaskell은 다음 유형을 추론합니다.

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

c, 문자열 목록으로 간주됩니다. 분명히 그것은 readString을 기대하는 어떤 함수로도 전달되거나 전달 될 수 없습니다 .

대신에

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

목록에 정확히 3 개의 항목이 있어야하는 경우 또는

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

≥3 품목이 허용되는 경우.

또한 (2), 표현

makeGroceryItem a read b read c

makeGroceryItem5 개의 인수 받는 것으로 해석되며 그 중 2 개는 read함수입니다. 괄호를 사용해야합니다.

makeGroceryItem a (read b) (read c)

이 질문에 이미 답변이 있지만 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정확히 하나의 요소가있는 목록을 반환합니다. 변환 된 값과 변환 할 수없는 추가 문자로 구성된 튜플입니다. 실패 reads하면 빈 목록을 반환합니다.

성공과 실패에 대한 패턴 매치가 쉽고, 얼굴에 터지지 않습니다!


두가지:

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

:과 같지 않기 때문 입니다 ++.

Meanwhile on the right hand side --- the side that's giving you the error message you see --- you have to group expressions using brackets. Otherwise parse is interpreted as being a value you want to pass to makeGroceryItem, so the compiler complains when you try to pass 5 arguments to a function that only takes 3 parameters.


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)

-> prints 16.0

Thats how I solved this task in my project.

참고URL : https://stackoverflow.com/questions/2468410/convert-string-to-integer-float-in-haskell

반응형