Skip to content

Commit b52bb5c

Browse files
JordanMartinezsigma-andexrhendric
authored
Update repo for PureScript v0.15.0 release (documentationjs#438)
* First draft of documentation update for v0.15 (documentationjs#421) * First draft of documentation update for v0.15 * Describe ambiguous matches in instance chains (documentationjs#392) * Update tool versions * Update parsing library changelog * Update 0.15 guides to account for `Stream.write` breaking change Co-authored-by: sigma-andex <[email protected]> Co-authored-by: Ryan Hendrickson <[email protected]>
1 parent 0e18f50 commit b52bb5c

File tree

8 files changed

+117
-81
lines changed

8 files changed

+117
-81
lines changed

guides/FFI-Tips.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ foreign import joinPath :: FilePath -> FilePath -> FilePath
1111
```
1212

1313
```javascript
14-
exports.joinPath = function(start) {
14+
export function joinPath(start) {
1515
return function(end) {
1616
return require('path').join(start, end);
1717
};
@@ -27,7 +27,7 @@ foreign import joinPathImpl :: Fn2 FilePath FilePath FilePath
2727
```
2828

2929
```javascript
30-
exports.joinPathImpl = require('path').join;
30+
export { join as joinPathImpl } from 'path';
3131
```
3232

3333
However, these `Fn0`..`Fn10` types cannot be applied as normal PureScript functions, they require a corresponding `runFn0`..`runFn10` call to execute. The `runFn` definitions essentially do the work of taking a multi-argument function and returning a curried version for you.
@@ -62,7 +62,7 @@ doSomething fn x = runFn2 doSomethingImpl fn x
6262
```
6363

6464
```javascript
65-
exports.doSomethingImpl = function(fn, x) {
65+
export function doSomethingImpl(fn, x) {
6666
if (fn(x)) {
6767
return Data_Maybe.Just.create(x);
6868
} else {
@@ -104,7 +104,7 @@ showSomething x = runFn3 showSomethingImpl isJust show x
104104
```
105105

106106
```javascript
107-
exports.doSomethingImpl = function(isJust, show, value) {
107+
export function doSomethingImpl(isJust, show, value) {
108108
if (isJust(value)) {
109109
return "It's something: " + show(value);
110110
} else {
@@ -122,7 +122,7 @@ By moving the `show` reference out to `showSomething` the compiler will pick the
122122
In order to avoid prematurely evaluating effects (or evaluating effects that should not be evaluated at all), PureScript wraps them in constant functions:
123123

124124
```javascript
125-
exports.myEffect = function() {
125+
export function myEffect() {
126126
return doSomethingEffectful(1, 2, 3);
127127
}
128128
```

guides/FFI.md

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,11 @@ This function finds the greatest common divisor of two numbers by repeated subtr
3333
To understand how this function can be called from Javascript, it is important to realize that PureScript functions always get turned into Javascript functions _of a single argument_, so we need to apply its arguments one-by-one:
3434

3535
``` javascript
36-
var Test = require('Test');
37-
Test.gcd(15)(20);
36+
import { gcd } from 'Test';
37+
gcd(15)(20);
3838
```
3939

40-
Here, I am assuming that the code was compiled with `psc`, which compiles PureScript modules to CommonJS modules. For that reason, I was able to reference the `gcd` function on the `Test` object, after importing the `Test` module using `require`.
41-
42-
You might also like to bundle JavaScript code for the browser, using `purs bundle`. In that case, you would access the `Test` module on the global namespace, which defaults to `PS`:
43-
44-
``` javascript
45-
var Test = PS.Test;
46-
Test.gcd(15)(20);
47-
```
40+
Here, I am assuming that the code was compiled with `psc`, which compiles PureScript modules to ES modules. For that reason, I was able to import the `gcd` function from the `Test` module.
4841

4942
#### Understanding Name Generation
5043

@@ -85,14 +78,12 @@ The general rule regarding types is that you can enforce as little or as much ty
8578
In PureScript, JavaScript code is wrapped using a _foreign module_. A foreign module is just a CommonJS module which is associated with a PureScript module. Foreign modules are required to adhere to certain conventions:
8679

8780
- The name of the foreign module must be the same as its companion PureScript module, with its extension changed to `.js`. This associates the foreign module with the PureScript module.
88-
- All exports must be of the form `exports.name = value;`, specified at the top level.
81+
- All exports must be of the form `export const name = value;` respectively `export function name() { ... }` for functions, specified at the top level.
8982

9083
Here is an example, where we export a function which computes interest amounts from a foreign module:
9184

9285
```javascript
93-
"use strict";
94-
95-
exports.calculateInterest = function(amount) {
86+
export function calculateInterest(amount) {
9687
return amount * 0.1;
9788
};
9889
```
@@ -114,9 +105,7 @@ PureScript functions are curried by default, so Javascript functions of multiple
114105
Suppose we wanted to modify our `calculateInterest` function to take a second argument:
115106

116107
```javascript
117-
"use strict";
118-
119-
exports.calculateInterest = function(amount, months) {
108+
export function calculateInterest(amount, months) {
120109
return amount * Math.exp(0.1, months);
121110
};
122111
```
@@ -141,9 +130,7 @@ calculateInterestCurried = runFn2 calculateInterest
141130
An alternative is to use curried functions in the native module, using multiple nested functions, each with a single argument, as the runtime representation of the function type constructor `(->)` dictates:
142131

143132
```javascript
144-
"use strict";
145-
146-
exports.calculateInterest = function(amount) {
133+
export function calculateInterest(amount) {
147134
return function(months) {
148135
return amount * Math.exp(0.1, months);
149136
};

guides/Getting-Started.md

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,10 @@ The `spago run` command can be used to compile and run the `Main` module:
256256
Spago can be used to turn our PureScript code into JavaScript suitable for use in the web browser by using the `spago bundle-app` command:
257257

258258
$ spago bundle-app
259-
...
260-
Build succeeded.
261-
Bundle succeeded and output file to index.js
259+
index.js 11.8kb
260+
261+
⚡ Done in 14ms
262+
[info] Bundle succeeded and output file to index.js
262263

263264
All the code in the `src` directory and any project dependencies have been compiled to JavaScript. The resulting code is bundled as `index.js` and has also had any unused code removed, a process known as dead code elimination. This `index.js` file can now be included in an HTML document.
264265

@@ -284,41 +285,35 @@ Open this `index.html` file in your web browser. The page will be blank, but if
284285
If you open `index.js`, you should see a few compiled modules which look like this:
285286

286287
```javascript
287-
// Generated by purs bundle 0.13.6
288-
var PS = {};
289-
290-
// ...
291-
292-
(function($PS) {
293-
"use strict";
294-
$PS["Euler"] = $PS["Euler"] || {};
295-
var exports = $PS["Euler"];
296-
var Data_EuclideanRing = $PS["Data.EuclideanRing"];
297-
var Data_Foldable = $PS["Data.Foldable"];
298-
var Data_List = $PS["Data.List"];
299-
var Data_List_Types = $PS["Data.List.Types"];
300-
var Data_Semiring = $PS["Data.Semiring"];
301-
var ns = Data_List.range(0)(999);
302-
var multiples = Data_List.filter(function (n) {
303-
return Data_EuclideanRing.mod(Data_EuclideanRing.euclideanRingInt)(n)(3) === 0 || Data_EuclideanRing.mod(Data_EuclideanRing.euclideanRingInt)(n)(5) === 0;
304-
})(ns);
305-
var answer = Data_Foldable.sum(Data_List_Types.foldableList)(Data_Semiring.semiringInt)(multiples);
306-
exports["answer"] = answer;
307-
})(PS);
308-
309-
(function($PS) {
310-
// Generated by purs version 0.13.6
311-
"use strict";
312-
$PS["Main"] = $PS["Main"] || {};
313-
var exports = $PS["Main"];
314-
var Data_Show = $PS["Data.Show"];
315-
var Effect_Console = $PS["Effect.Console"];
316-
var Euler = $PS["Euler"];
317-
var main = Effect_Console.log("The answer is " + Data_Show.show(Data_Show.showInt)(Euler.answer));
318-
exports["main"] = main;
319-
})(PS);
320-
321-
PS["Main"].main();
288+
(() => {
289+
// output/Data.Show/foreign.js
290+
var showIntImpl = function(n) {
291+
return n.toString();
292+
};
293+
294+
...
295+
296+
// output/Euler/index.js
297+
var ns = /* @__PURE__ */ function() {
298+
return range2(0)(999);
299+
}();
300+
var multiples = /* @__PURE__ */ function() {
301+
return filter(function(n) {
302+
return mod(euclideanRingInt)(n)(3) === 0 || mod(euclideanRingInt)(n)(5) === 0;
303+
})(ns);
304+
}();
305+
var answer = /* @__PURE__ */ function() {
306+
return sum(foldableList)(semiringInt)(multiples);
307+
}();
308+
309+
// output/Main/index.js
310+
var main = /* @__PURE__ */ function() {
311+
return log("The answer is " + show(showInt)(answer));
312+
}();
313+
314+
// <stdin>
315+
main();
316+
})();
322317
```
323318

324319
This illustrates a few points about the way the PureScript compiler generates JavaScript code:
@@ -331,17 +326,17 @@ This illustrates a few points about the way the PureScript compiler generates Ja
331326

332327
These points are important since they mean that PureScript generates simple, understandable code. The code generation process, in general, is quite a shallow transformation. It takes relatively little understanding of the language to predict what JavaScript code will be generated for a particular input.
333328

334-
### Compiling CommonJS Modules
329+
### Compiling ES Modules
335330

336-
Spago can also be used to generate CommonJS modules from PureScript code. This can be useful when using NodeJS, or just when developing a larger project which uses CommonJS modules to break code into smaller components.
331+
Spago can also be used to generate ES modules from PureScript code. This can be useful when using NodeJS, or just when developing a larger project which uses ES modules to break code into smaller components.
337332

338-
To build CommonJS modules, use the `spago build` command:
333+
To build ES modules, use the `spago build` command:
339334

340335
$ spago build
341336
...
342337
Build succeeded.
343338

344-
The generated modules will be placed in the `output` directory by default. Each PureScript module will be compiled to its own CommonJS module, in its own subdirectory.
339+
The generated modules will be placed in the `output` directory by default. Each PureScript module will be compiled to its own ES module, in its own subdirectory.
345340

346341
### What Next?
347342

guides/PSCi.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ $ spago init # Initialize a Spago environment
1414
$ spago repl # Fire up the interpreter psci
1515
1616
...
17-
PSCi, version 0.13.6
17+
PSCi, version 0.15.0
1818
Type :? for help
1919
2020
import Prelude

guides/PureScript-Without-Node.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,24 +59,27 @@ Compiling Effect.Console
5959

6060
#### Bundling JavaScript for the Browser
6161

62-
To bundle the generated Javascript code, we will use `purs bundle`.
62+
To bundle the generated Javascript code into a single file, we will use `spago bundle`.
6363

64-
`purs bundle` takes a collection of CommonJS module files as input, and generates a single JavaScript file.
64+
`spago bundle-app` take the module with the main as input, and generates a single self-contained JavaScript file.
6565

66-
Run `purs bundle` with the following arguments:
66+
Run `spago bundle-app` with the following arguments:
6767

68-
```text
69-
$ purs bundle output/*/{index,foreign}.js --module Main --main Main
68+
```bash
69+
$ spago bundle-app --main Main --to index.js
7070
```
7171

72-
The `--module` argument specifies an _entry-point_ module, which will be used to determine dead code which can be removed. For our purposes, we only care about bundling the CommonJS module corresponding to the Main PureScript module and its transitive dependencies.
73-
7472
The `--main` argument will make the output JavaScript file an executable by adding a line of JavaScript to it which runs the `main` function in the specified module.
7573

76-
If everything worked, you should see about 100 lines of JavaScript printed out. This can optionally be redirected to a file with the `--output`/`-o` argument.
74+
If you want to bundle for Node.js, you can use the following command:
75+
76+
```bash
77+
spago bundle-app --main Main --to index.js --platform node
78+
```
79+
You should be able to execute the generated JavaScript using Node.js.
7780

78-
You should be able to execute the generated JavaScript using NodeJS. If your PureScript code uses FFI files which `require` NPM modules, you'll need to use a JavaScript bundler, like Webpack or Browserify, before running it in the browser.
81+
For more information, see the [spago documentation](https://www.github.com/purescript/spago).
7982

8083
#### Conclusion
8184

82-
I've shown how it's possible to get started with PureScript without using the tools from the NodeJS ecosystem. Obviously, for larger projects, it takes some work to manage library dependencies this way, which is why the PureScript community has decided to reuse existing tools. However, if you need to avoid those tools for any reason, it is possible to script some standard tasks without them.
85+
I've shown how it's possible to get started with PureScript without using the tools from the Node.JS ecosystem. Obviously, for larger projects, it takes some work to manage library dependencies this way, which is why the PureScript community has decided to reuse existing tools. However, if you need to avoid those tools for any reason, it is possible to script some standard tasks without them.

language/Type-Classes.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,26 @@ main = do
5353
log $ myShow MysteryItem -- Invalid
5454
```
5555

56+
When type variables are present in the constraint being solved, the question of whether an instance in a chain matches is a little subtle. A type variable in the constraint is treated existentially—it represents some concrete type, but the constraint solver isn't allowed to assume that it is any particular type. This means that, when evaluating an instance as a solution for a particular constraint, there are three possible outcomes for the instance: it can match, it can fail to match, or it can be ambiguous. An ambiguous instance is one that could match the constraint only if one or more of the variables in the constraint happened to represent a particular type.
57+
58+
```purescript
59+
class MyShow a where
60+
myShow :: a -> String
61+
62+
instance showStringTuple :: MyShow a => MyShow (Tuple String a) where
63+
myShow (Tuple s a) = s <> ": " <> myShow a
64+
65+
else instance showA :: MyShow a where
66+
myShow _ = "Invalid"
67+
68+
f :: forall l r. Tuple l r -> String
69+
f = myShow -- error: no instance found
70+
```
71+
72+
In this example, `f` needs an instance of `MyShow (Tuple l r)`. The `showStringTuple` is an ambiguous match for this constraint, because it would only match if `l` represented the type `String`. But `f` needs an implementation that will work for all `l`, so this can't be used as a full match.
73+
74+
Ambiguous instances are mostly treated the same as an instance that fails to match, with this exception. If an instance in an instance chain fails to match, the compiler will try the next instance in the chain. But if an instance in an instance chain is an ambiguous match, the compiler will not consider any more instances in that chain. In the above example, the compiler will report that no instance was found for `MyShow (Tuple l r)` in `f`, even though the `showA` instance could have been a match, because the ambiguous `showStringTuple` prevents `showA` from being considered.
75+
5676
## Multi-Parameter Type Classes
5777

5878
TODO. For now, see the section in [PureScript by Example](https://book.purescript.org/chapter6.html#multi-parameter-type-classes).

migration-guides/0.15-Ecosystem-Update.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,19 @@ Breaking changes:
308308

309309
To get the `ParserT` internal state, call `getParserT` instead of `get`.
310310

311-
- Add the `anyTill` primitive `String` combinator. ([#186](https://github.com/purescript-contrib/purescript-parsing/pull/186) by @jamesdbrock)
311+
New features:
312+
- Add the `anyTill` primitive `String` combinator. (#186 by @jamesdbrock)
313+
- Add the `Parsing.String.Replace` module, copied from
314+
https://github.com/jamesdbrock/purescript-parsing-replace (#188 by @jamesdbrock)
315+
`streamEditT` can be written in terms of `replaceT`.
316+
317+
`streamEditT input sep editor = replaceT input (sep >>= editor >>> lift)`
318+
319+
(#188 by @jamesdbrock, #194 by @jamesdbrock)
320+
- Add the `advance` and `manyIndex` combinators. (#193 by @jamesdbrock)
321+
322+
Bugfixes:
323+
- Improve correctness and speed of `number` and `intDecimal`. (#189 by @jamesdbrock)
312324

313325
### `profunctor-lenses`
314326

@@ -432,5 +444,8 @@ Breaking changes:
432444

433445
### `node-streams`
434446

447+
Breaking changes:
448+
- Update `write` callback to include `Error` arg ([#40](https://github.com/purescript-node/purescript-node-streams/pull/40) by @JordanMartinez)
449+
435450
Other improvements:
436451
- Fix `Gzip` example ([#17](https://github.com/purescript-node/purescript-node-streams/pull/17), [#36](https://github.com/purescript-node/purescript-node-streams/pull/36) by @matthewleon and @JordanMartinez)

migration-guides/0.15-Migration-Guide.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ Compiler releases are often accompanied by breaking changes in the core librarie
77
## Tooling
88

99
- `purescript-psa` does not need to be updated.
10-
- `spago` needs to be updated to `vT.B.D`.
10+
- `spago` needs to be updated to `v0.20.8`.
1111
- `pulp` needs to be updated to `v16.0.0`.
12-
- `purs-tidy` needs to be updated to `vT.B.D`.
12+
- `purs-tidy`:
13+
- `0.7.2`, the latest version as of this writing, will only format your `0.15.0` code if you are not using type-level integers syntax.
14+
- A future release should address this issue.
1315

1416
## ES modules migration guide
1517

@@ -736,6 +738,20 @@ Key differences are:
736738

737739
## Breaking Changes in the `purescript-node` libraries
738740

741+
### Expose the `Error` arg to `Stream.write`/`Stream.writeString (`purescript-node-streams`)
742+
743+
The `Stream.write` and `Stream.writeString` have a callback function. The type signature for this binding was inaccurate because an `Error` arg is passed to that function but the type signature is `Effect Unit` rather than `Error -> Effect Unit`.
744+
745+
This type signature was updated to be more accurate
746+
```diff
747+
-write :: forall r. Writable r -> Buffer -> Effect Unit -> Effect Boolean
748+
+write :: forall r. Writable r -> Buffer -> (Error -> Effect Unit) -> Effect Boolean
749+
```
750+
751+
**To fix**:
752+
- if you want to keep your current behavior, wrap your `Effect Unit` code in `const` (e.g. `pure unit` -> `const $ pure unit`)
753+
- if you want to use the `Error` arg, you can use `\err -> ...`
754+
739755
### Expose the `recursive` field in `mkdir'`'s options arg (`purescript-node-fs`/`purescript-node-fs-aff`)
740756

741757
Previously, `mkdir` did not expose all the fields in the options arg. So, trying to run something like `mkdir "foo/bar/baz" { recursive: true }` wasn't possible without writing your own FFI to `mkdir`. The `recursive` option has now been exposed.

0 commit comments

Comments
 (0)