You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Mar 25, 2021. It is now read-only.
The PureScript compiler has supported _generic deriving_ in some form since version 0.7.3, thanks to [Gershom Bazerman](http://gbaz.github.io/). However, since then, it has gone through several iterations, and the current version (implemented in the `purescript-generics-rep` library) makes it possible to have the compiler derive a wide variety of boilerplate code based on types. One example of this is the serialization and deserialization of JSON, and in the following guide we'll show how to use the [`purescript-foreign-generic`](https://github.com/paf31/purescript-foreign-generic) library to create such functions using generics.
19
-
20
-
### Generics Overview
21
-
22
-
PureScript's generics are supported by the `purescript-generics-rep` library, and in particular, the `Data.Generic.Rep.Generic` type class:
18
+
PureScript's generics are supported by the `Data.Generic.Rep.Generic` type class:
23
19
24
20
```purescript
25
21
class Generic a rep | a -> rep where
@@ -33,7 +29,7 @@ There are three interesting things here:
33
29
-`from` converts a regular value into the representation type.
34
30
-`to` converts a representation value back into a regular value.
35
31
36
-
`purescript-generics-rep` provides standard representation types which can be used to represent any `data` types which can be expressed in PureScript code.
32
+
This library provides standard representation types which can be used to represent any `data` types which can be expressed in PureScript code.
37
33
38
34
It is possible to write out `Generic` instances for our own types by hand, but doing so is very laborious. Instead, we can _derive_ instances by using the `derive` keyword:
39
35
@@ -73,76 +69,6 @@ instance semigroupPerson :: Semigroup Person where
73
69
append = genericAppend
74
70
```
75
71
76
-
### Handling Foreign Data
77
-
78
-
The `purescript-foreign` library is used in PureScript to handle untrusted external data, and to turn such data into typed values. This functionality is represented by the `Decode` type class in the `purescript-foreign-generic` library:
79
-
80
-
```purescript
81
-
class Decode a where
82
-
decode :: Foreign -> F a
83
-
```
84
-
85
-
`Decode` instances are a good example of boilerplate code. In most cases, we proceed based on the structure of the type in question. For example, here is one possible implementation of `Decode` for our `Person` type, using the new _field puns_ feature:
86
-
87
-
```haskell
88
-
instancedecodePerson::DecodePersonwhere
89
-
decode value =do
90
-
name <- value !"name"
91
-
location <- value !"location"
92
-
pure$Person { name, location }
93
-
```
94
-
95
-
This is not too bad, but real-world records often contain many more fields. Also, it would be nice if we could be sure that the corresponding _encoding_ function would always generate compatible data. Let's see how to verify the same data using `Generic`, which will solve both of these problems.
96
-
97
-
The `purescript-foreign-generic` library defines a function `genericDecode`, with the following type:
98
-
99
-
```haskell
100
-
genericDecode
101
-
::forallarep
102
-
.Genericarep
103
-
=>GenericDecoderep
104
-
=>Options
105
-
->Foreign
106
-
->Fa
107
-
```
108
-
109
-
The `Options` type here is based on the options record from Haskell's`aeson` library.For our purposes, the default options will work, but we need to turn on the `unwrapSingleConstructors` option, so that our `newtype` constructor gets ignored during serialization:
Right (Person { name: "John Smith", location: "USA" })
131
-
```
132
-
133
-
### Generating JSON
134
-
135
-
Just as `genericDecode` can be used to _read_ well-typed data, the `genericEncode` and `genericEncodeJSON` functions can be used to produce the appropriate data or JSON from a PureScript value. The generated `genericDecode` and `genericEncode` functions are inverse to each other for any given input type.
136
-
137
-
In PSCi, we can test JSON generation for our `Person` data type:
One application of this technique is to produce and consume JSON for use with JSON web services, using generics to reduce the amount of boilerplate model code needed.
145
-
146
72
### Performance Concerns
147
73
148
74
Generic deriving can be very convenient for code generation, but it comes with a performance penalty. Consider defining a `Show` instance using `genericShow` - instead of simply converting our data type directly to a `String`, we first convert it to the representation type, and then convert that representation into a `String`. Creating this intermediate structure comes with a cost.
0 commit comments