Skip to content
This repository was archived by the owner on Mar 25, 2021. It is now read-only.

Commit 02ec353

Browse files
committed
Small edits and remove foreign data section
1 parent 03193e5 commit 02ec353

File tree

1 file changed

+2
-76
lines changed

1 file changed

+2
-76
lines changed

README.md

Lines changed: 2 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@ bower install purescript-generics-rep
1515

1616
## Introduction
1717

18-
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:
2319

2420
```purescript
2521
class Generic a rep | a -> rep where
@@ -33,7 +29,7 @@ There are three interesting things here:
3329
- `from` converts a regular value into the representation type.
3430
- `to` converts a representation value back into a regular value.
3531

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.
3733

3834
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:
3935

@@ -73,76 +69,6 @@ instance semigroupPerson :: Semigroup Person where
7369
append = genericAppend
7470
```
7571

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-
instance decodePerson :: Decode Person where
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-
:: forall a rep
102-
. Generic a rep
103-
=> GenericDecode rep
104-
=> Options
105-
-> Foreign
106-
-> F a
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:
110-
111-
``` haskell
112-
myOptions :: Options
113-
myOptions = defaultOptions { unwrapSingleConstructors = true }
114-
```
115-
116-
With this, our `Decode` instance is as simple as:
117-
118-
``` haskell
119-
instance decodePerson :: Decode Person where
120-
decode = genericDecode myOptions
121-
```
122-
123-
We can test out this instance in PSCi as follows:
124-
125-
```text
126-
> import Data.Generic.Rep
127-
> import Data.Generic.Rep.Show
128-
129-
> map genericShow (decodeJSON "{ 'name': 'John Smith', 'location': 'USA' }" :: Either ForeignError Person)
130-
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:
138-
139-
```text
140-
> encodeJSON (Person { name: "John Smith", location: "USA" })
141-
"{ 'name': 'John Smith', location: 'USA' }"
142-
```
143-
144-
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-
14672
### Performance Concerns
14773

14874
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

Comments
 (0)