Ответ 1
Проблема заключается в том, что Text.JSON
не знает, как преобразовать данные JSON
в
ваш тип данных Person
. Для этого вам нужно либо сделать Person
, либо
экземпляр класса JSON
, или вы можете использовать Text.JSON.Generic
и
DeriveDataTypeable
, чтобы выполнить эту работу для вас.
Дженерики
Метод Text.JSON.Generic
будет читать структуру JSON
, основанную на
структура вашего типа данных.
{-# LANGUAGE DeriveDataTypeable #-}
import Text.JSON.Generic
data Address = Address
{ house :: Integer
, street :: String
, city :: String
, state :: String
, zip :: Integer
} deriving (Show, Data, Typeable)
data Person = Person
{ name :: String
, age :: Integer
, address :: Address
} deriving (Show, Data, Typeable)
aa :: String
aa = "{\"name\": \"some body\", \"age\" : 23, \"address\" : {\"house\" : 285, \"street\" : \"7th Ave.\", \"city\" : \"New York\", \"state\" : \"New York\", \"zip\" : 10001}}"
main = print (decodeJSON aa :: Person)
Этот метод работает очень хорошо, если вы не против сопоставления имен полей
в вашей структуре данных в формате JSON
.
В стороне, вам не нужно писать такие функции, как getName
, getAddress
,
и getState
. Имена поля в вашем типе записи являются accesor
функции.
∀ x. x ⊦ :t house
house :: Address -> Integer
∀ x. x ⊦ :t address
address :: Person -> Address
Экземпляр JSON
В качестве альтернативы вы можете воспользоваться большой дорогой и реализовать свой собственный экземпляр
класс JSON
.
import Control.Applicative
import Control.Monad
import Text.JSON
data Address = Address
{ house :: Integer
, street :: String
, city :: String
, state :: String
-- Renamed so as not to conflict with zip from Prelude
, zipC :: Integer
} deriving (Show)
data Person = Person
{ name :: String
, age :: Integer
, address :: Address
} deriving (Show)
aa :: String
aa = "{\"name\": \"some body\", \"age\" : 23, \"address\" : {\"house\" : 285, \"street\" : \"7th Ave.\", \"city\" : \"New York\", \"state\" : \"New York\", \"zip\" : 10001}}"
-- For convenience
(!) :: (JSON a) => JSObject JSValue -> String -> Result a
(!) = flip valFromObj
instance JSON Address where
-- Keep the compiler quiet
showJSON = undefined
readJSON (JSObject obj) =
Address <$>
obj ! "house" <*>
obj ! "street" <*>
obj ! "city" <*>
obj ! "state" <*>
obj ! "zip"
readJSON _ = mzero
instance JSON Person where
-- Keep the compiler quiet
showJSON = undefined
readJSON (JSObject obj) =
Person <$>
obj ! "name" <*>
obj ! "age" <*>
obj ! "address"
readJSON _ = mzero
main = print (decode aa :: Result Person)
Это использует тот факт, что тип Result
является Applicative
легко
цепочка вместе с запросами на значение JSObject
.
Это немного больше работы, но это дает вам больший контроль над структурой
JSON
, если вам нужно иметь дело с JSON
, что приведет к установлению стиля
нарушения из-за странных названий полей.