@@ -16,3 +16,142 @@ bower install purescript-argonaut-core
1616## Documentation
1717
1818Module documentation is [ published on Pursuit] ( http://pursuit.purescript.org/packages/purescript-argonaut-core ) .
19+
20+ ## Tutorial
21+
22+ Some of Argonaut's functions might seem a bit arcane at first, so it can help
23+ to understand the underlying design decisions which make it the way it is.
24+
25+ One approach for modelling JSON values would be to define an ADT, like this:
26+
27+ ``` purescript
28+ data Json
29+ = JNull
30+ | JBoolean Boolean
31+ | JArray (Array Json)
32+ | JObject (StrMap Json)
33+ [...]
34+ ```
35+
36+ And indeed, some might even say this is the obvious approach.
37+
38+ Because Argonaut is written with the compilation target of JavaScript in mind,
39+ it takes a slightly different approach, which is to reuse the existing data
40+ types which JavaScript already provides. This way, the result of JavaScript's
41+ ` JSON.stringify ` function is already a ` Json ` value, and no extra processing is
42+ needed before you can start operating on it. This ought to help your program
43+ both in terms of speed and memory churn.
44+
45+ Much of the design of Argonaut follows naturally from this design decision.
46+
47+ ### Introducing Json values
48+
49+ (Or, where do ` Json ` values come from?)
50+
51+ Usually, a ` Json ` value will be introduced into your program via either the FFI
52+ or via the construction functions in ` Data.Argonaut.Core ` . Here are some
53+ examples:
54+
55+ ``` javascript
56+ // In an FFI module.
57+ exports .someNumber = 23.6 ;
58+ exports .someBoolean = false ;
59+ exports .someObject = {people: [{name: " john" }, {name: " jane" }],
60+ ` ` `
61+
62+ ` ` ` purescript
63+ foreign import someNumber :: Json
64+ foreign import someBoolean :: Json
65+ foreign import someObject :: Json
66+ ` ` `
67+
68+ Generally, if a JavaScript value could be returned from a call to
69+ ` JSON .stringify ` , it's fine to import it from the FFI as ` Json` . So, for
70+ example, objects, booleans, numbers, strings, and arrays are all fine, but
71+ functions are not.
72+
73+ The construction functions (that is, ` fromX` , or ` jsonX` ) can be used as
74+ follows:
75+
76+ ` ` ` purescript
77+ import Data.Tuple (Tuple(..))
78+ import Data.StrMap as StrMap
79+ import Data.Argonaut.Core as A
80+
81+ someNumber = A .fromNumber 23.6
82+ someBoolean = A .fromBoolean false
83+ someObject = A .fromObject (StrMap .fromFoldable [
84+ Tuple " people" (A .fromArray [
85+ A .jsonSingletonObject " name" (A .fromString " john" ),
86+ A .jsonSingletonObject " name" (A .fromString " jane" )
87+ ])
88+ ])
89+ ` ` `
90+
91+ ### Eliminating/matching on ` Json` values
92+
93+ We can perform case analysis for ` Json` values using the ` foldJson` function.
94+ This function is necessary because ` Json` is not an algebraic data type. If
95+ ` Json` were an algebraic data type, we would not have as much need for this
96+ function, because we could perform pattern matching with a ` case ... of `
97+ expression instead.
98+
99+ For example, imagine we had the following values defined in JavaScript and
100+ imported via the FFI:
101+
102+ ` ` ` javascript
103+ exports .someNumber = 0.0 ;
104+ exports .someArray = [0.0 , {foo: ' bar' }, false ];
105+ exports .someObject = {foo: 1 , bar: [2 ,2 ]};
106+ ` ` `
107+
108+ Then we can match on them in PureScript using ` foldJson` :
109+
110+ ` ` ` purescript
111+ foreign import someNumber :: Json
112+ foreign import someArray :: Json
113+ foreign import someObject :: Json
114+
115+ basicInfo :: Json - > String
116+ basicInfo = foldJson
117+ (const "It was null ")
118+ (\b - > " Got a boolean: " <>
119+ if b then " it was true!" else " It was false." )
120+ (\x - > " Got a number: " <> show x)
121+ (\s - > " Got a string, which was " <> Data .String .length s <>
122+ " characters long." )
123+ (\xs - > " Got an array, which had " <> Data .Array .length xs <>
124+ " items." )
125+ (\obj - > " Got an object, which had " <> Data .StrMap .size obj <>
126+ " items." )
127+ ` ` `
128+
129+ ` ` ` purescript
130+ basicInfo someNumber -- => " Got a number: 0.0"
131+ basicInfo someArray -- => " Got an array, which had 3 items."
132+ basicInfo someObject -- => " Got an object, which had 2 items."
133+ ` ` `
134+
135+ All the other functions for matching on ` Json` values can be expressed in terms
136+ of ` foldJson` , but a few others are provided for convenience. For example, the
137+ ` foldJsonX` functions can be used to match on a specific type. The first
138+ argument acts as a default value, to be used if the ` Json` value turned out not
139+ to be that type. For example, we can write a function which tests whether a
140+ JSON value is the string "lol" like this:
141+
142+ ` ` ` purescript
143+ isJsonLol = foldJsonString false (_ == " lol" )
144+ ` ` `
145+
146+ If the ` Json` value is not a string, the default ` false ` is used. Otherwise,
147+ we test whether the string is equal to "lol".
148+
149+ The ` toX` functions also occupy a similar role. We could have written
150+ ` isJsonLol` like this, too:
151+
152+ ` ` ` purescript
153+ isJsonLol json =
154+ case toString json of
155+ Just str - > str == " lol"
156+ Nothing - > false
157+ ` ` `
0 commit comments