我想要做的是真的很簡單。我使用Haskell的Text.JSON被認爲是醜陋的?
我想轉換以下JSON,我正在從外部源獲取:
[{"symbol": "sym1", "description": "desc1"}
{"symbol": "sym1", "description": "desc1"}]
爲以下幾種類型:
data Symbols = Symbols [Symbol]
type Symbol = (String, String)
我最後寫了下面的代碼使用Text.JSON:
instance JSON Symbols where
readJSON (JSArray arr) = either Error (Ok . Symbols) $ resultToEither (f arr [])
where
f ((JSObject obj):vs) acc = either Error (\x -> f vs (x:acc)) $ resultToEither (g (fromJSObject obj) [])
f [] acc = Ok $ reverse acc
f _ acc = Error "Invalid symbol/description list"
g ((name, JSString val):vs) acc = g vs ((name, fromJSString val):acc)
g [] acc = valg acc
g _ acc = Error "Invalid symbol/description record"
valg xs = case (sym, desc) of
(Nothing, _) -> Error "Record is missing symbol"
(_, Nothing) -> Error "Record is missing description"
(Just sym', Just desc') -> Ok (sym', desc')
where
sym = lookup "symbol" xs
desc = lookup "description" xs
showJSON (Symbols syms) = JSArray $ map f syms
where
f (sym, desc) = JSObject $ toJSObject [("symbol", JSString $ toJSString sym),
("description", JSString $ toJSString desc)]
這已經到了我所寫過的最不雅的哈斯克爾。 readJSON
只是看起來不對。當然,showJSON
大大縮短了,但是這個JSString $ toJSString
和JSObject $ toJSObject
這些東西我不得不放在這裏?和resultToEither
?
我使用Text.JSON錯誤嗎?有沒有更好的辦法?
好吧,這是更喜歡它。感謝羅馬和格拉澤的澄清和想法,我已經得到readJSON
。在每一點上,它都會檢測到格式不正確的JSON,並輸出錯誤而不是拋出異常。
instance JSON Symbols where
readJSON o = fmap Symbols (readJSON o >>= mapM f)
where
f (JSObject o) = (,) <$> valFromObj "symbol" o <*> valFromObj "description" o
f _ = Error "Unable to read object"
我可以改變標題,但我不認爲它改變了問題。在這裏沒有涉及monad簡化的地方,你會如何使用mapM? – qrest 2010-09-10 06:27:29
'Result' *是* monad(http://hackage.haskell.org/packages/archive/json/0.4.4/doc/html/Text-JSON.html#t:Result)。我現在將用示例代碼更新我的答案。請注意,我放棄了一些錯誤消息 - 如果需要,您可以恢復它們。 – 2010-09-10 06:54:02
爲了改善錯誤處理(我展示的代碼可能會拋出異常),編寫模式匹配函數的安全版本(用於JSObject和JSString),它將在模式匹配失敗時返回錯誤並單點使用它們。 – 2010-09-10 07:02:07