Analyzujem niektoré údaje, ktoré nekontrolujem. Mám hodnoty, ktoré sú radom reťazcov. Môže to byť buď normálny reťazec, reťazcové znázornenie čísla alebo číslo s úvodzovkami.
["This is just a string", ""5"", "3"]
Chcel by som napísať funkciu toValue
ktorý ich prevádza na vhodný typ, ktorý sa má previesť na JSON.
toValue :: (ToJSON a) => String -> a
toValue (if a number) = parseInt
toValue (if a quoted number) = parseInt . stripQuotes
toValue _ = id
Chcel by som odškrtnúť úvodzovky, ak je to číslo obklopené úvodzovkami, potom ich skonvertovať na číslo, ak číslo, inak ho odovzdať späť ako reťazec.
Môžem to urobiť so zhodou vzorov? Iným spôsobom?
odpovede:
3 pre odpoveď č. 1 import Data.Char
import Data.Bool
parse a@(""":n:""":[]) = bool (Left a) (Right (read [n] :: Int)) (isNumber n)
parse a@(""":n:m:""":[]) = bool (Left a) (Right (read [n,n] :: Int)) (isNumber n && isNumber m)
parse a@(n:[]) = bool (Left a) (Right (read [n] :: Int)) (isNumber n)
parse a@(n:m:[]) = bool (Left a) (Right (read [n,n] :: Int)) (isNumber n && isNumber m)
parse xs = Left xs
> map parse ["This is just a string", ""5"", "3"]
[Left "This is just a string",Right 5,Right 3]
potom môžete použiť either
funkcia od Data.Either
modul na kódovanie čísla (Práva) a reťazca (Lefts) do JSON.
-1 pre odpoveď č. 2
Písanie funkcie toValue :: ToJSON a => String -> a
ako navrhujete, nie je také ťažké: jednoducho urobme to toValue
metóda triedy ToJSON
class ToJSON a where
toValue :: String -> a
a potom definujte inštanciu pre Int
ako
instance ToJSON Int where
toValue s@(""" : _) = read (read s) -- with quotes
toValue s = read s -- without quotes
Príklad pre String
je trochu viac zapojený (ako String
je synonymom pre [Char]
), ale v žiadnom prípade raketová veda:
class ToJSONList a where
toValues :: String -> [a]
instance ToJSONList Char where
toValues = id
instance ToJSONList a => ToJSON [a] where
toValue = toValues
Teraz, pri testovaní v interaktívnej relácii, máme:
> toValue "This is just a string" :: String
"This is just a string"
> toValue ""5"" :: Int
5
> toValue "3" :: Int
3
Z vašej otázky sa však zdá, že máte prípad použitia, ktorý nie je takouto funkciou dostatočne podporený toValue
, t. j. na konverziu všetkých prvkov zoznamu na príslušné zastúpenie JSON. Pravdepodobne budete chcieť zaviesť algebraický dátový typ reprezentujúci hodnoty JSON:
data JSON = JInt Int | JString String deriving Show
a potom fungujú voči spoločnosti JSON, ktorá riadi ich najvhodnejšie zastúpenie JSON:
toJSON :: String -> JSON
toJSON s =
case reads s of
[(n, "")] -> JInt n -- Int, no quotes
_ -> case reads s of
[(s, "")] -> case reads s of
[(n, "")] -> JInt n -- Int, quotes
_ -> JString s -- String, quotes
_ -> JString s -- String, no quotes
Na zodpovedanie tejto časti otázky je potrebné odpovedať:táto funkcia je definovaná iba (vnoreným) porovnaním vzorov. Ak sa však (gramatika) jazyka, ktorý musíte analyzovať, stáva zložitejším, potom iba celočíselnými literálmi, citovanými celočíselnými literármi a reťazcovými literálmi, tento spôsob definovania analyzátorov sa rýchlo stáva neohrabanou a náchylnou na chyby a možno budete chcieť začať pozerať sa do kombinátory syntaktického analyzátora alebo generátory syntaktického analyzátora potom.
Pre váš jednoduchý jazyk hodnôt JSON je to však stále v poriadku. Tu je jednoduchý príklad interaktívnej relácie:
> map toJSON ["This is just a string", ""5"", "3"]
[JString "This is just a string",JInt 5,JInt 3]