Skip to content

Commit 13a9f12

Browse files
author
Harry Garrood
committed
Move docs to README.md
1 parent ee0b827 commit 13a9f12

File tree

2 files changed

+153
-147
lines changed

2 files changed

+153
-147
lines changed

README.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,157 @@ bower install purescript-effect
1313

1414
## Documentation
1515

16+
Values in PureScript do not have side-effects by default. This package provides
17+
the standard type PureScript uses to handle "native" effects, i.e. effects
18+
which are provided by the runtime system, and which cannot be emulated by pure
19+
functions. Some examples of native effects are:
20+
21+
* Console IO
22+
* Random number generation
23+
* Exceptions
24+
* Reading/writing mutable state
25+
26+
And in the browser:
27+
28+
* DOM manipulation
29+
* XMLHttpRequest / AJAX calls
30+
* Interacting with a websocket
31+
* Writing/reading to/from local storage
32+
33+
All of these things may be represented in PureScript by the `Effect` type.
34+
A value of the type `Effect a` represents a computation which may perform
35+
some native effects, and which produces a value of the type `a` once it
36+
finishes. For example, the module `Effect.Random` from `purescript-random`
37+
exports a value `random`, whose type is `Effect Number`. When run, this
38+
effect produces a random number between 0 and 1. To give another example,
39+
the module `Effect.Console` exports a function `log`, whose type is
40+
`String -> Effect Unit`. This function takes a string and produces an
41+
effect which, when run, prints the provided string to the console.
42+
43+
```purescript
44+
module RandomExample where
45+
import Prelude
46+
import Effect (Effect)
47+
import Effect.Random (random)
48+
import Effect.Console (log)
49+
50+
printRandom :: Effect Unit
51+
printRandom = do
52+
n <- random
53+
log (show n)
54+
```
55+
56+
In this example, `printRandom` is an effect which generates a random
57+
number between 0 and 1 and prints it to the console. You can test it out
58+
in the repl:
59+
60+
```
61+
> import RandomExample
62+
> printRandom
63+
0.71831842260513870
64+
unit
65+
```
66+
67+
The `unit` is there because all effects must produce a value. When there
68+
is nothing useful to return, we usually use the type `Unit`, which has
69+
just one value: `unit`.
70+
71+
### Effects and Purity
72+
73+
Note that using `Effect` does not compromise the purity of your program.
74+
Functions which make use of `Effect` are still pure, in the sense that
75+
all functions will return the same outputs given the same inputs.
76+
77+
This is enabled by having the `Effect` type denote _values_ which can be
78+
run to produce native effects; an `Effect a` is a computation which has
79+
not yet necessarily been performed. In fact, there is no way of "running"
80+
an `Effect` manually; we cannot provide a (safe) function of the type
81+
`forall a. Effect a -> a`, because such a function would violate purity;
82+
it could produce different outputs given the same input. (Note that there
83+
is actually such a function in the module `Effect.Unsafe`, but it is best
84+
avoided outside of exceptional circumstances.)
85+
86+
Instead, the recommended way of "running" an effect is to include it as
87+
part of your program's `main` value.
88+
89+
A consequence of being able to represent native effects purely using
90+
`Effect` is that you can construct and pass `Effect` values around your
91+
programs freely. For example, we can write functions which can decide
92+
whether to run a given effect just once, many times, or not at all:
93+
94+
```purescript
95+
-- | Runs an effect three times, provided that the given condition is
96+
-- | true.
97+
thriceIf :: Boolean -> Effect Unit -> Effect Unit
98+
thriceIf cond effect =
99+
if cond
100+
then do
101+
effect
102+
effect
103+
effect
104+
else
105+
pure unit
106+
```
107+
108+
### Using Effects via the Foreign Function Interface
109+
110+
A computation of type `Effect a` is implemented in JavaScript as a
111+
zero-argument function whose body is expected to perform its side-effects
112+
before finally returning its result. For example, suppose we wanted a
113+
computation which would increment a global counter and return the new
114+
result each time it was run. We can implement this as follows:
115+
116+
```purescript
117+
-- Counter.purs
118+
foreign import incrCounter :: Effect Int
119+
```
120+
121+
and in the corresponding JavaScript module:
122+
123+
```javascript
124+
// Counter.js
125+
exports.incrCounter = function() {
126+
if (!window.globalCounter) {
127+
window.globalCounter = 0;
128+
}
129+
return ++window.globalCounter;
130+
}
131+
```
132+
133+
For more information about the FFI (Foreign Function Interface), see
134+
the [documentation repository](https://github.com/purescript/documentation).
135+
This package also provides a module
136+
[Effect.Uncurried](https://pursuit.purescript.org/packages/purescript-effect/docs/Effect.Uncurried)
137+
to simplify the process of making uncurried effectful JavaScript functions
138+
available to PureScript via the FFI.
139+
140+
### The Effect type is Magic
141+
142+
The PureScript compiler has special support for the `Effect` monad.
143+
Ordinarily, a chain of monadic binds might result in poor performance when
144+
executed. However, the compiler can generate code for the `Effect` monad
145+
without explicit calls to the monadic bind function `>>=`.
146+
147+
Take the random number generation example from above. When compiled, the
148+
compiler produces the following JavaScript:
149+
150+
```javascript
151+
var printRandom = function __do() {
152+
var $0 = Effect_Random.random();
153+
return Effect_Console.log(Data_Show.show(Data_Show.showNumber)($0))();
154+
};
155+
```
156+
157+
whereas a more naive compiler might, for instance, produce:
158+
```javascript
159+
var printRandom = Control_Bind.bind(Effect.bindEffect)(Effect_Random.random)(function ($0) {
160+
return Effect_Console.log(Data_Show.show(Data_Show.showNumber)($0));
161+
});
162+
```
163+
164+
While this is a small improvement, the benefit is greater when using
165+
multiple nested calls to `>>=`.
166+
167+
### API reference
168+
16169
Module documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-effect).

src/Effect.purs

Lines changed: 0 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,6 @@
11
-- | This module provides the `Effect` type, which is used to represent
22
-- | _native_ effects. The `Effect` type provides a typed API for effectful
33
-- | computations, while at the same time generating efficient JavaScript.
4-
-- |
5-
-- | As in Haskell, values in PureScript do not have side-effects by default.
6-
-- | This module provides the standard type PureScript uses to handle "native"
7-
-- | effects, i.e. effects which are provided by the runtime system, and which
8-
-- | cannot be emulated by pure functions. Some examples of native effects are:
9-
-- |
10-
-- | * Console IO
11-
-- | * Random number generation
12-
-- | * Exceptions
13-
-- | * Reading/writing mutable state
14-
-- |
15-
-- | And in the browser:
16-
-- |
17-
-- | * DOM manipulation
18-
-- | * XMLHttpRequest / AJAX calls
19-
-- | * Interacting with a websocket
20-
-- | * Writing/reading to/from local storage
21-
-- |
22-
-- | All of these things may be represented in PureScript by the `Effect` type.
23-
-- | A value of the type `Effect a` represents a computation which may perform
24-
-- | some native effects, and which produces a value of the type `a` once it
25-
-- | finishes. For example, the module `Effect.Random` from `purescript-random`
26-
-- | exports a value `random`, whose type is `Effect Number`. When run, this
27-
-- | effect produces a random number between 0 and 1. To give another example,
28-
-- | the module `Effect.Console` exports a function `log`, whose type is
29-
-- | `String -> Effect Unit`. This function takes a string and produces an
30-
-- | effect which, when run, prints the provided string to the console.
31-
-- |
32-
-- | ```purescript
33-
-- | module RandomExample where
34-
-- | import Prelude
35-
-- | import Effect (Effect)
36-
-- | import Effect.Random (random)
37-
-- | import Effect.Console (log)
38-
-- |
39-
-- | printRandom :: Effect Unit
40-
-- | printRandom = do
41-
-- | n <- random
42-
-- | log (show n)
43-
-- | ```
44-
-- |
45-
-- | In this example, `printRandom` is an effect which generates a random
46-
-- | number between 0 and 1 and prints it to the console. You can test it out
47-
-- | in the repl:
48-
-- |
49-
-- | ```
50-
-- | > import RandomExample
51-
-- | > printRandom
52-
-- | 0.71831842260513870
53-
-- | unit
54-
-- | ```
55-
-- |
56-
-- | The `unit` is there because all effects must produce a value. When there
57-
-- | is nothing useful to return, we usually use the type `Unit`, which has
58-
-- | just one value: `unit`.
59-
-- |
60-
-- | #### Effects and Purity
61-
-- |
62-
-- | Note that using `Effect` does not compromise the purity of your program.
63-
-- | Functions which make use of `Effect` are still pure, in the sense that
64-
-- | all functions will return the same outputs given the same inputs.
65-
-- |
66-
-- | This is enabled by having the `Effect` type denote _values_ which can be
67-
-- | run to produce native effects; an `Effect a` is a computation which has
68-
-- | not yet necessarily been performed. In fact, there is no way of "running"
69-
-- | an `Effect` manually; we cannot provide a (safe) function of the type
70-
-- | `forall a. Effect a -> a`, because such a function would violate purity;
71-
-- | it could produce different outputs given the same input. (Note that there
72-
-- | is actually such a function in the module `Effect.Unsafe`, but it is best
73-
-- | avoided outside of exceptional circumstances.)
74-
-- |
75-
-- | Instead, the recommended way of "running" an effect is to include it as
76-
-- | part of your program's `main` value.
77-
-- |
78-
-- | A consequence of being able to represent native effects purely using
79-
-- | `Effect` is that you can construct and pass `Effect` values around your
80-
-- | programs freely. For example, we can write functions which can decide
81-
-- | whether to run a given effect just once, many times, or not at all:
82-
-- |
83-
-- | ```purescript
84-
-- | -- | Runs an effect three times, provided that the given condition is
85-
-- | -- | true.
86-
-- | thriceIf :: Boolean -> Effect Unit -> Effect Unit
87-
-- | thriceIf cond effect =
88-
-- | if cond
89-
-- | then do
90-
-- | effect
91-
-- | effect
92-
-- | effect
93-
-- | else
94-
-- | pure unit
95-
-- | ```
96-
-- |
97-
-- | #### Using Effects via the Foreign Function Interface
98-
-- |
99-
-- | A computation of type `Effect a` is implemented in JavaScript as a
100-
-- | zero-argument function whose body is expected to perform its side-effects
101-
-- | before finally returning its result. For example, suppose we wanted a
102-
-- | computation which would increment a global counter and return the new
103-
-- | result each time it was run. We can implement this as follows:
104-
-- |
105-
-- | ```purescript
106-
-- | -- Counter.purs
107-
-- | foreign import incrCounter :: Effect Int
108-
-- | ```
109-
-- |
110-
-- | and in the corresponding JavaScript module:
111-
-- |
112-
-- | ```javascript
113-
-- | // Counter.js
114-
-- | exports.incrCounter = function() {
115-
-- | if (!window.globalCounter) {
116-
-- | window.globalCounter = 0;
117-
-- | }
118-
-- | return ++window.globalCounter;
119-
-- | }
120-
-- | ```
121-
-- |
122-
-- | For more information about the FFI (Foreign Function Interface), see
123-
-- | the [documentation repository](https://github.com/purescript/documentation).
124-
-- |
125-
-- | #### The Effect type is Magic
126-
-- |
127-
-- | The PureScript compiler has special support for the `Effect` monad.
128-
-- | Ordinarily, a chain of monadic binds might result in poor performance when
129-
-- | executed. However, the compiler can generate code for the `Effect` monad
130-
-- | without explicit calls to the monadic bind function `>>=`.
131-
-- |
132-
-- | Take the random number generation example from above. When compiled, the
133-
-- | compiler produces the following JavaScript:
134-
-- |
135-
-- | ```javascript
136-
-- | var printRandom = function __do() {
137-
-- | var $0 = Effect_Random.random();
138-
-- | return Effect_Console.log(Data_Show.show(Data_Show.showNumber)($0))();
139-
-- | };
140-
-- | ```
141-
-- |
142-
-- | whereas a more naive compiler might, for instance, produce:
143-
-- | ```javascript
144-
-- | var printRandom = Control_Bind.bind(Effect.bindEffect)(Effect_Random.random)(function ($0) {
145-
-- | return Effect_Console.log(Data_Show.show(Data_Show.showNumber)($0));
146-
-- | });
147-
-- | ```
148-
-- |
149-
-- | While this is a small improvement, the benefit is greater when using
150-
-- | multiple nested calls to `>>=`.
1514
module Effect
1525
( Effect
1536
, untilE, whileE, forE, foreachE

0 commit comments

Comments
 (0)