@@ -16,3 +16,142 @@ bower install purescript-argonaut-core
16
16
## Documentation
17
17
18
18
Module 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