source - fileadmin.cs.lth.sefileadmin.cs.lth.se/cs/education/edan40/lectures/json.4.pdf ·...
TRANSCRIPT
SimpleJSON
SimpleJSON (or creating useful modules)
Jacek MalecDept. of Computer Science, Lund University, Sweden
April 2, 2019
Jacek Malec, http://rss.cs.lth.se 1(28)
SimpleJSON
Source
The source material for this lecture is Chapter 5 in the book
“Real World Haskell”
by Bryan O’Sullivan, Don Stewart, and John Goerzen
available in its entirety at http://book.realworldhaskell.org
O’Reilly, 2008
Jacek Malec, http://rss.cs.lth.se 2(28)
SimpleJSON
What are modules and why should I care?
modules provide librariesstandardized way to package useful codeinteroperabilitywide distributionthree levels:
1 GHC standard libraries (Haskell 2010)2 Haskell Platform Libraries3 Hackage database
Library installer for Haskell: cabalThe Common Architecture for Building Applications andLibrariesBrowse hackage.haskell.org for more...
Jacek Malec, http://rss.cs.lth.se 3(28)
SimpleJSON
What is JSON and why should I care?
Lightweight data exchange formatJSON = Java Script Object NotationCommunication between a server and applets on client sidewww.json.org, RFC 4627 (www.ietf.org/rfc/rfc4627.txt)simple types (string, number, boolean, null) and compoundones (arrays and objects)an object is a collection of (name : JSON value) pairsand that’s it!
Jacek Malec, http://rss.cs.lth.se 4(28)
SimpleJSON
Data constructors
data JValue = JString String
| JNumber Double
| JBool Bool
| JNull
| JObject [(String, JValue)]
| JArray [JValue]
deriving (Eq, Ord, Show)
Jacek Malec, http://rss.cs.lth.se 5(28)
SimpleJSON
Data renderers
-- file: ch05/PutJSON.hs
module PutJSON where
import Data.List (intercalate)
import SimpleJSON
renderJValue :: JValue -> String
renderJValue (JString s) = show s
renderJValue (JNumber n) = show n
renderJValue (JBool True) = "true"
renderJValue (JBool False) = "false"
renderJValue JNull = "null"
Jacek Malec, http://rss.cs.lth.se 6(28)
SimpleJSON
Data renderers
renderJValue (JObject o) = "{" ++ pairs o ++ "}"where pairs [] = ""
pairs ps = intercalate ", " (map renderPair ps)renderPair (k,v) = show k ++ ": " ++ renderJValue v
renderJValue (JArray a) = "[" ++ values a ++ "]"where values [] = ""
values vs = intercalate ", " (map renderJValue vs)
Jacek Malec, http://rss.cs.lth.se 7(28)
SimpleJSON
A bit more to do
-- file: ch05/PutJSON.hs
putJValue :: JValue -> IO ()
putJValue v = putStrLn (renderJValue v)
Now, the following:module Main () where
import SimpleJSONimport PutJSON
main = putJValue (JObject [("foo", JNumber 1),("bar", JBool False)])
yields
{"foo": 1.0, "bar": false}
Jacek Malec, http://rss.cs.lth.se 8(28)
SimpleJSON
We are ready! Not yet.
We have a representation for all JSON objectsWe can render them as strings (before possibly sending out)Why anything else?
It can be done more generally.
Let’s introduce pretty-printingfor machine readability (JSON)for human readability
Module will be called Prettify.
Jacek Malec, http://rss.cs.lth.se 9(28)
SimpleJSON
New version of renderer
-- file: ch05/PrettyJSON.hsrenderJValue :: JValue -> DocrenderJValue (JBool True) = text "true"renderJValue (JBool False) = text "false"renderJValue JNull = text "null"renderJValue (JNumber num) = double numrenderJValue (JString str) = string str
Jacek Malec, http://rss.cs.lth.se 10(28)
SimpleJSON
Interactiveness
-- file: ch05/PrettyStub.hsimport SimpleJSON
data Doc = ToBeDefinedderiving (Show)
string :: String -> Docstring str = undefined
text :: String -> Doctext str = undefined
double :: Double -> Docdouble num = undefined
Jacek Malec, http://rss.cs.lth.se 11(28)
SimpleJSON
Pretty printing a string
-- file: ch05/PrettyJSON.hsstring :: String -> Docstring = enclose ’"’ ’"’ . hcat . map oneChar
enclose :: Char -> Char -> Doc -> Docenclose left right x = char left <> x <> char right
(<>) :: Doc -> Doc -> Doca <> b = undefined
char :: Char -> Docchar c = undefined
hcat :: [Doc] -> Dochcat xs = undefined
Jacek Malec, http://rss.cs.lth.se 12(28)
SimpleJSON
Pretty printing a string
-- file: ch05/PrettyJSON.hsoneChar :: Char -> DoconeChar c = case lookup c simpleEscapes of
Just r -> text rNothing | mustEscape c -> hexEscape c
| otherwise -> char cwhere mustEscape c = c < ’ ’ || c == ’\x7f’ || c > ’\xff’
simpleEscapes :: [(Char, String)]simpleEscapes = zipWith ch "\b\n\f\r\t\\\"/" "bnfrt\\\"/"
where ch a b = (a, [’\\’,b])
hexEscape :: Char -> DochexEscape c | d < 0x10000 = smallHex d
| otherwise = astral (d - 0x10000)where d = ord c
Jacek Malec, http://rss.cs.lth.se 13(28)
SimpleJSON
Pretty printing complex objects
-- file: ch05/PrettyJSON.hsseries :: Char -> Char -> (a -> Doc) -> [a] -> Docseries open close item = enclose open close
. fsep . punctuate (char ’,’) . map item
-- file: ch05/PrettyStub.hsfsep :: [Doc] -> Docfsep xs = undefined
punctuate :: Doc -> [Doc] -> [Doc]punctuate p [] = []punctuate p [d] = [d]punctuate p (d:ds) = (d <> p) : punctuate p ds
Jacek Malec, http://rss.cs.lth.se 14(28)
SimpleJSON
Pretty printing complex objects
-- file: ch05/PrettyJSON.hsrenderJValue (JArray ary) = series ’[’ ’]’ renderJValue ary
renderJValue (JObject obj) = series ’{’ ’}’ field objwhere field (name,val) = string name
<> text ": "<> renderJValue val
Jacek Malec, http://rss.cs.lth.se 15(28)
SimpleJSON
Module header
-- file: ch05/PrettyJSON.hsmodule PrettyJSON
(renderJValue
) where
import Numeric (showHex)import Data.Char (ord)import Data.Bits (shiftR, (.&.))
import SimpleJSON (JValue(..))import Prettify (Doc, (<>), char, double, fsep, hcat, punctuate,
text, compact, pretty)
Jacek Malec, http://rss.cs.lth.se 16(28)
SimpleJSON
Concretizing Prettify.hs
-- file: ch05/Prettify.hsdata Doc = Empty
| Char Char| Text String| Line| Concat Doc Doc| Union Doc Doc
deriving (Show,Eq)
empty :: Docempty = Empty
char :: Char -> Docchar c = Char c
Jacek Malec, http://rss.cs.lth.se 17(28)
SimpleJSON
Concretizing Prettify.hs
-- file: ch05/Prettify.hstext :: String -> Doctext "" = Emptytext s = Text s
double :: Double -> Docdouble d = text (show d)
line :: Docline = Line
(<>) :: Doc -> Doc -> DocEmpty <> y = yx <> Empty = xx <> y = x ‘Concat‘ y
Jacek Malec, http://rss.cs.lth.se 18(28)
SimpleJSON
Concretizing Prettify.hs
-- file: ch05/Prettify.hshcat :: [Doc] -> Dochcat = fold (<>)
fold :: (Doc -> Doc -> Doc) -> [Doc] -> Docfold f = foldr f empty
fsep :: [Doc] -> Docfsep = fold (</>)
(</>) :: Doc -> Doc -> Docx </> y = x <> softline <> y
softline :: Docsoftline = group line
Jacek Malec, http://rss.cs.lth.se 19(28)
SimpleJSON
Keeping alternatives
-- file: ch05/Prettify.hsgroup :: Doc -> Docgroup x = flatten x ‘Union‘ x
flatten :: Doc -> Docflatten (x ‘Concat‘ y) = flatten x ‘Concat‘ flatten yflatten Line = Char ’ ’flatten (x ‘Union‘ _) = flatten xflatten other = other
Jacek Malec, http://rss.cs.lth.se 20(28)
SimpleJSON
The real work: machine
-- file: ch05/Prettify.hscompact :: Doc -> Stringcompact x = transform [x]
where transform [] = ""transform (d:ds) =
case d ofEmpty -> transform dsChar c -> c : transform dsText s -> s ++ transform dsLine -> ’\n’ : transform dsa ‘Concat‘ b -> transform (a:b:ds)_ ‘Union‘ b -> transform (b:ds)
Jacek Malec, http://rss.cs.lth.se 21(28)
SimpleJSON
The real work: man
-- file: ch05/Prettify.hspretty :: Int -> Doc -> Stringpretty width x = best 0 [x]
where best col (d:ds) =case d of
Empty -> best col dsChar c -> c : best (col + 1) dsText s -> s ++ best (col + length s) dsLine -> ’\n’ : best 0 dsa ‘Concat‘ b -> best col (a:b:ds)a ‘Union‘ b -> nicest col (best col (a:ds))
(best col (b:ds))best _ _ = ""nicest col a b | (width - least) ‘fits‘ a = a
| otherwise = bwhere least = min width col
Jacek Malec, http://rss.cs.lth.se 22(28)
SimpleJSON
The real work: man
-- file: ch05/Prettify.hsfits :: Int -> String -> Boolw ‘fits‘ _ | w < 0 = Falsew ‘fits‘ "" = Truew ‘fits‘ (’\n’:_) = Truew ‘fits‘ (c:cs) = (w - 1) ‘fits‘ cs
Jacek Malec, http://rss.cs.lth.se 23(28)
SimpleJSON
Results
*PrettyJSON> let value = renderJValue (JObject [("f",JNumber 1),
("q",JBool True)])
*PrettyJSON> :t valuevalue :: Doc*PrettyJSON> putStrLn (pretty 10 value){"f": 1.0,"q": true}*PrettyJSON> putStrLn (pretty 20 value){"f": 1.0, "q": true}*PrettyJSON> putStrLn (pretty 30 value){"f": 1.0, "q": true }*PrettyJSON>
Jacek Malec, http://rss.cs.lth.se 24(28)
SimpleJSON
Cabal
The Common Architecture for Building Applications and Libraries
Cabal organizes software in packagesA package is a library and possibly several executableprogramspackage description: *.cabalpackage setup file: Setup.hsthen the usual triple:runghc Setup {configure, build, install}
or sometimes just cabal install foobar
Jacek Malec, http://rss.cs.lth.se 25(28)
SimpleJSON
mypretty.cabal
Name: myprettyVersion: 0.1Synopsis: My pretty printing library, with JSON supportDescription:
A simple pretty printing library that illustrates how todevelop a Haskell library.
Author: Real World HaskellMaintainer: [email protected]: >= 1.2library
Exposed-Modules: PrettifyPrettyJSONSimpleJSON
Build-Depends: base >= 2.0
Jacek Malec, http://rss.cs.lth.se 26(28)
SimpleJSON
Hackage 2010
Jacek Malec, http://rss.cs.lth.se 27(28)
SimpleJSON
Hackage 2019
Jacek Malec, http://rss.cs.lth.se 28(28)