Haskell簡明教程(五):處理JSON
這一系列是我學習Learn You a Haskell For Great Good
之後,總結,編寫的學習筆記。
這個系列主要分為五個部分:
- ofollow,noindex" target="_blank">從遞迴說起
- 從命令式語言進行抽象
- Haskell初步:語法
- Haskell進階:Monoid, Applicative, Monad
本文有參考 《Real World Haskell》
Haskell如何表示JSON
json 是一種資料表現形式,來源於 javascript。JSON中有四種基本的值的型別:
- number
- boolean: true/false
- string
- null
此外有兩種容器型別:
- array
- object
那麼Haskell我們需要如何表示成JSON呢?我們需要一個 value constructor 加上Haskell自帶的型別來表示:
data JValue = JNumber Integer | JString String | JBoolean Bool | JNull | JArray [JValue] | JObject [(String, JValue)] deriving (Show, Ord, Eq)
那麼我們要如何輸出JSON呢?其型別肯定是這樣的:
echoJValue :: JValue -> String
我們分別為 string, bool, null, number 定義好如何輸出成JSON:
echoJValue (JNumber i) = show i echoJValue (JString s) = show s echoJValue (JBoolean True) = "true" echoJValue (JBoolean False) = "false" echoJValue JNull = "null"
array該怎麼處理?輸出 "[" 之後輸出array中的內容,然後輸出 "]",所以是:
echoJValue (JArray a) = "[" ++ handleArray a ++ "]" where handleArray [] = "" handleArray a = intercalate ", " (map echoJValue a)
而object則是:
echoJValue (JObject a) = "{" ++ handleObject a ++ "}" where handleObject [] = "" handleObject a = intercalate ", " (map handleKV a) handleKV (k,v) = k ++ ": " ++ echoJValue v
此處我們需要匯入Data.List
中的 intercalate 函式:
Prelude> :m Data.List Prelude Data.List> :t intercalate intercalate :: [a] -> [[a]] -> [a] Prelude Data.List> intercalate ", " ["hello", "world"] "hello, world"
於是我們便可以輸出自定義的JSON了。
Prelude> :l JSON [1 of 1] Compiling Main( JSON.hs, interpreted ) Ok, 1 module loaded. *Main> JNull JNull *Main> JNumber 1 JNumber 1 *Main> JString "hello" JString "hello" *Main> JBoolean True JBoolean True *Main> JBoolean False JBoolean False *Main> JArray [JBoolean True, JBoolean False] JArray [JBoolean True,JBoolean False] *Main> echoJValue $ JArray [JBoolean True, JBoolean False] "[true, false]" *Main> echoJValue $ JObject [("hello", JNumber 1), ("world", JString "world")] "{hello: 1, world: \"world\"}"
我們可以把整個檔案做成一個Module:
module JSON ( JValue(..), echoJValue ) where import Data.List (intercalate) data JValue = JNumber Integer | JString String | JBoolean Bool | JNull | JArray [JValue] | JObject [(String, JValue)] deriving (Show, Ord, Eq) echoJValue :: JValue -> String echoJValue (JNumber i) = show i echoJValue (JString s) = show s echoJValue (JBoolean True) = "true" echoJValue (JBoolean False) = "false" echoJValue JNull = "null" echoJValue (JArray a) = "[" ++ handleArray a ++ "]" where handleArray [] = "" handleArray a = intercalate ", " (map echoJValue a) echoJValue (JObject a) = "{" ++ handleObject a ++ "}" where handleObject [] = "" handleObject a = intercalate ", " (map handleKV a) handleKV (k,v) = k ++ ": " ++ echoJValue v
那我們該要怎樣 pretty print呢?這就留作思考吧 :) (提示:Haskell的世界,遞迴總是那麼重要)
總結
到此Haskell教程便結束了,我們從最開始的命令式語言如何抽象,到介紹Haskell的基本語法和要素, TypeClass, Functor, Applicative, Monoid, Monad,到隨後我們封裝一個簡單的JSON模組。簡略的 瀏覽了一下Haskell的面貌,但是Haskell抽象程度很高,為此付出的代價便是不那麼容易一眼就看出來, 有時候甚至需要來回看,來回琢磨才能領會其中的意義。
之後我將會寫一些散篇,主要是Haskell和現實世界的應用,或者是Haskell的原始碼分析。
參考資料: