Skip to content

Commit 749e370

Browse files
Make ps-0.15.x-v0.33.0 (#619)
* Update build history; note spago difference * Add initial explanation for VTAs * Fix monad state instantiation * Fix Effect example * Link to falsify and other prop test links * Link to Free Boolean Cube * fp-ts' migration guide * Add GADT-related link * Fix file name * Update spago/purs to latest
1 parent c140536 commit 749e370

File tree

40 files changed

+1098
-42
lines changed

40 files changed

+1098
-42
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ jobs:
1010
runs-on: ubuntu-latest
1111

1212
steps:
13-
- uses: actions/checkout@v2
13+
- uses: actions/checkout@v3
1414

1515
- name: Set up PureScript toolchain
1616
uses: purescript-contrib/setup-purescript@main
1717
with:
18-
purescript: "0.15.7"
18+
purescript: "0.15.13"
1919

2020
- name: Cache PureScript dependencies
21-
uses: actions/cache@v2
21+
uses: actions/cache@v3
2222
with:
2323
key: ${{ runner.os }}-spago-${{ hashFiles('packages.dhall') }}
2424
path: |
@@ -38,9 +38,9 @@ jobs:
3838
22-Projects/.spago
3939
4040
- name: Set up Node toolchain
41-
uses: actions/setup-node@v2
41+
uses: actions/setup-node@v3
4242
with:
43-
node-version: "16"
43+
node-version: "lts/*"
4444

4545
- name: Install dependencies
4646
run: |

01-Getting-Started/01-Why-Learn-PureScript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ One of the main issues with JavaScript is a poor type system. Many errors aren't
6565

6666
TypeScript seems to address this type safety issue. Just consider its name! However, a few people who are using PureScript now have said this about TypeScript: "You might as well be writing Javascript." TypeScript does not provide any real guarantees; it only pretends. PureScript does provide such guarantees.
6767

68+
- [`fp-ts`'s Migration guide from PureScript to TypeScript](https://gcanti.github.io/fp-ts/guides/purescript.html). This is helpful for seeing 1) how much more TypeScript code it takes to implement the same feature in PureScript, and 2) how the resulting syntax IMO is of lesser quality and clarity than the corresponding PureScript code is.
6869
- [TypeScript vs PureScript: Not All Compilers Are Created Equal](https://blog.logrocket.com/typescript-vs-purescript-not-all-compilers-are-created-equal-c16dadaa7d3e)
6970
- [JavaScript, TypeScript, and PureScript](https://www.youtube.com/watch?v=JTEfpNtEoSA) or "Why TypeScript only 'pretends' to have types."
7071
- [Various examples comparing PureScript and TypeScript](https://discourse.purescript.org/t/type-system-showdown-purescript-and-typescript/2084)

01-Getting-Started/04-Install-Guide.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Unlike the manual install, `nvm` properly handles the npm prefix for you. So, yo
4848
Once you have installed `npm`, we can use it to install everything in one command:
4949

5050
```sh
51-
npm i -g [email protected].7 spago@0.20.9 esbuild@0.15.7 purs-tidy@0.9.2 purs-backend-es@1.3.1 [email protected]
51+
npm i -g [email protected].13 spago@0.21.0 esbuild@0.19.8 purs-tidy@0.10.0 purs-backend-es@1.4.2 [email protected]
5252
```
5353

5454

@@ -63,9 +63,9 @@ npm i -g purs-backend-es
6363
The following commands should now work:
6464

6565
```sh
66-
purs --version # 0.15.7
67-
spago --version # 0.20.9
68-
esbuild --version # 0.15.7
66+
purs --version # 0.15.13
67+
spago --version # 0.21.0
68+
esbuild --version # 0.19.8
6969
```
7070

7171
### Building This Project

03-Build-Tools/Readme.md

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ This folder accomplishes the following:
1010

1111
## History: How We Got Here
1212

13-
The following explanation does not cover all the tools used in PureScript's ecosystem. However it provides context for later files. In short, `spago` is both the official dependency manager and build tool. `bower` can be thought of as a deprecated dependency manager; the community is in the process of building a registry that will replace the Bower registry since it no longer accepts uploads. `pulp` is a build tool that uses `bower`; its usage will become more common again once the registry is built.
13+
The following explanation does not cover all the tools used in PureScript's ecosystem. However it provides context for later files.
14+
15+
In short, `spago` is both the official dependency manager and build tool. It was originally written in Haskell. It's currently being rewritten in PureScript. The Haskell version is called `spago-legacy` whereas the rewrite is the alpha `spago`. Whenever this repo mentions `spago`, it's always in reference to `spago-legacy`.
16+
17+
There are two other tools that are only around because alpha `spago` hasn't been finished yet. `bower` can be thought of as a deprecated dependency manager; the community used this tool because it provided a registry. `pulp` is a build tool that uses `bower`; its usage has become less frequent because of the migration towards `spago`.
1418

1519
### Phase 1: Initial Tooling
1620

@@ -24,6 +28,8 @@ Bodil Stokke (with later contributions from Harry Garrood) later wrote a tool ca
2428
- publish libraries and their docs
2529
- easily bump the project's version
2630

31+
This is why most of the "core" libraries (PureScript libraries stored under the `purescript` GitHub organization) still have `bower.json` files as their dependencies.
32+
2733
### Phase 2: The `psc-package` Experiment
2834

2935
`Bower` worked fine, but there were a few user-interface issues that made it difficult to use, especially when a new PureScript release was made that included breaking changes.
@@ -40,38 +46,29 @@ See the below image to visualize this:
4046

4147
### Phase 3: Improving the `psc-package` Developer Workflow via `Spago`
4248

43-
From the above image, one should infer that using `pulp` and `bower` was overall easier to use and explain. Thus, Justin Woo and Fabrizo Ferrai started a project called `spago`. `spago` evolved out of `spacchetti` and reimplemented parts of `psc-package` into one program with a seamless developer workflow. While `psc-package` can still be used, it's better to use `spago`.
49+
From the above image, one should infer that using `pulp` and `bower` was overall easier to use and explain. Thus, Justin Woo and Fabrizo Ferrai started a project called `spago`. `spago` evolved out of `spacchetti` and reimplemented parts of `psc-package` into one program with a seamless developer workflow. While `psc-package` can still be used, it became better to use `spago`.
4450

4551
The below image summarizes the current state:
4652

4753
![Build Tool Relationships "Build Tool Relationships"](./assets/Build-Tool-Relationships--With-Spago.svg)
4854

4955
### Phase 4: `Spago` becomes mainstream while `psc-package` is less used
5056

51-
Spago dropped support for `psc-package` commands in the `v0.11.0` release. `psc-package` is still usable and is more or less feature-complete. However, no further work on it will be done. Rather, Spago has become the main dependency manager when utilizing package-sets.
57+
Spago dropped support for `psc-package` commands in the `v0.11.0` release. `psc-package` was still usable and was more or less feature-complete. However, no further work was being done on it. Rather, Spago had become the main dependency manager when utilizing package-sets.
5258

53-
The community is now split between `pulp` + `bower` workflows and `spago` workflows. One must still use `pulp` + `bower` if they want to do the following:
59+
At this point, part of the community used `pulp` + `bower` workflows while the rest used `spago` workflows. One must still use `pulp` + `bower` if they want to do the following:
5460
- publish their library's docs to Pursuit
5561
- include their library in a package set, so `spago` users can use it
5662

5763
### Phase 5: The need for a PureScript registry (Bower registry no longer accepts new uploads)
5864

5965
The Bower registry stopped accepting new uploads. The community quickly updated their tooling to workaround how libraries are published and installed. However, it was clear that PureScript now needed to create a registry.
6066

61-
Fabrizio Ferrai led the effort to build this registry with significant input from Harry Garrood. The registry is not yet complete, so the community is in this in-between stage.
62-
63-
Regardless, the following is still true:
64-
- most people are now using `spago`
65-
- the `pulp` + `bower` workflow is still needed to publish a library, but it works differently now.
66-
- See [these instructions for how to use `bower` to publish a library in this in-between context](https://discourse.purescript.org/t/up-to-date-instructions-for-publishing-new-packages/1953)
67-
- See the `Dependency Managers/Bower Explained` file for clarification on how to install packages as dependencies if one is using `bower`
68-
- Thomas has written a [Recommended Tooling for PureScript Applications](https://discourse.purescript.org/t/recommended-tooling-for-purescript-applications-in-2019/948) post.
69-
70-
See [The `bower` registry is no longer accepting package submissions](https://discourse.purescript.org/t/the-bower-registry-is-no-longer-accepting-package-submissions/1103/) for more context.
67+
Fabrizio Ferrai led the effort to build this registry with significant input from Harry Garrood. The registry is not yet complete, so the community is in this in-between stage. See [The `bower` registry is no longer accepting package submissions](https://discourse.purescript.org/t/the-bower-registry-is-no-longer-accepting-package-submissions/1103/) for more context.
7168

7269
### Phase 6: Updating JavaScript output to ES modules and delegating bundling to 3rd-party tools
7370

74-
In PureScript `0.15.0`, we stopped compiling PureScript source code to CommonJS modules and started compiling to ES modules. As a result, we dropped the buggy and broken bundler provided via `purs bundle` and instead directed endusers to use 3rd-party bundlers like `esbuild`, `webpack`, and `parecel`. Such bundlers often produced smaller bundles than `purs bundle`. Moreover, it gave the core team in charge of PureScript one less thing to maintain.
71+
In PureScript `0.15.0`, we stopped compiling PureScript source code to CommonJS modules and started compiling to ES modules. As a result, we dropped the buggy and broken bundler provided via `purs bundle` and instead directed end-users to use 3rd-party bundlers like `esbuild`, `webpack`, and `parcel`. Such bundlers often produced smaller bundles than `purs bundle`. Moreover, it gave the core team in charge of PureScript one less thing to maintain.
7572

7673
See the [0.15.0 Migration Guide](https://github.com/purescript/documentation/blob/master/migration-guides/0.15-Migration-Guide.md) for more details.
7774

@@ -81,15 +78,29 @@ While the Purescript compiler produces correct JavaScript code, there were a num
8178

8279
Soon after the time that PureScript `0.15.4` was released, a new project called `purs-backend-es` was released. This project works on the `CoreFn` representation and transforms it to JavaScript. However, it also optimizes the code significantly during this tranformation. For a few example, see [the `purs` and `purs-backend-es` comparison table in its README](https://github.com/aristanetworks/purescript-backend-optimizer#overview).
8380

84-
While this tool's main purpose is to produce optimized JavaScript code, it enables others to produce new backends. A backend is a target language to which PureScript can be compiled. Before this tool, every backend had to reinvent a lot of code to make it work for that language. With the underlying library, `purescript-backend-optimizer`, one can more easily produce a new backend.
81+
While this tool's main purpose is to produce optimized JavaScript code, it enables others to produce new backends more easily. A backend is a target language to which PureScript can be compiled. Before this tool, every backend had to reinvent a lot of code to make it work for that language. With the underlying library, `purescript-backend-optimizer`, one can more easily produce a new backend.
82+
83+
### Phase 8: The Registry and the Spago Rewrite
84+
85+
The Registry's speed of development was lackluster for quite some time. Fortunately, Thomas Honeyman made it a personal goal to see the Registry implemented. Since then, the Registry's development picked up and eventually became useable, although it's still not yet finished.
86+
87+
More recently, Fabrizio decided to rewrite Spago in PureScript. The main advantage of doing this was the ability to leverage the Registry codebase within Spago, allowing for a more seamless publishing workflow among other things. Such work is still on-going as of this writing (Sept 2023). But, the version of Spago written in Haskell is now known as "Spago Legacy" and the version written in PureScript is "Spago Next" because one install spago next via `npm i spago@next`.
88+
89+
## Spago: Haskell Legacy codebase or PureScript rewrite codebase?
90+
91+
| Type | NPM Package | Versions | Install via | Alternative |
92+
| - | - | - | - | - |
93+
| Legacy Spago | `spago` | `0.0.1` - `0.21.0` | `npm i spago` | `npm i spago-legacy` (installs `[email protected]` under binary name `spago-legacy`) |
94+
| Rewrite Spago | `spago` | `0.92.0` - `0.93.x` | `npm i spago@next` | - |
8595

8696
## Overview of Tools
8797

8898
| Name | Type/Usage | Comments | URL |
8999
| - | - | - | - |
90100
| purs | PureScript Compiler | Used to be called `psc` | -- |
91-
| spago | Build Tool | Front-end to `purs` and `package-set`-based projects | https://github.com/purescript/spago
92-
| pulp | Build Tool | Front-end to `purs`. Builds & publishes projects | https://github.com/purescript-contrib/pulp |
101+
| spago (rewrite) | Build Tool | Front-end to `purs`; `package-set`-based or dependency-range -based projects | https://github.com/purescript/spago |
102+
| spago (legacy) | Build Tool | Front-end to `purs` and `package-set`-based projects | https://github.com/purescript/spago-legacy
103+
| pulp | Build Tool | Front-end to `purs`. Builds & publishes projects (being deprecated) | https://github.com/purescript-contrib/pulp |
93104
| bower | Dependency Manager (being deprecated) | -- | https://bower.io/ |
94105
| purs-tidy | PureScript Formatter | -- | https://github.com/natefaubion/purescript-tidy
95106
| purs-backend-es | Produces optimized JavaScript from PureScript | Only intended for production-level usage | https://github.com/aristanetworks/purescript-backend-optimizer
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
module Syntax.Basic.VisibleTypeApplications.Intro where
2+
{-
3+
Visible Type Applications is a feature that only works completely
4+
as of PureScript 0.15.13. While it was supported earlier than that,
5+
there were a few bugs that hindered its usage. The content in this file
6+
and those that follow in this folder assume one is using PureScript 0.15.13.
7+
8+
Sometimes, using polymorphic code can be annoying
9+
because the compiler cannot infer what type you want to use. -}
10+
11+
polymorphicCode :: forall pleaseInferThisType. pleaseInferThisType -> Int
12+
polymorphicCode _someValue = 1
13+
{-
14+
problematicUsage :: Int
15+
problematicUsage = polymorphicCode []
16+
17+
The above code is commented out because it will produce a compiler error.
18+
The empty array is inferred by the compiler to have the type,
19+
`forall a. Array a`. Because there are no elements within the
20+
array, the compiler has no idea what the element type is. So, it infers it
21+
to the most generic type it can be: `forall a. a`.
22+
23+
In this situation, we would need to tell the compiler what that type is
24+
by doing one of two things:
25+
- indicating what the input type of `polymorphicCode` is
26+
- indicating what the element type of the empty array is
27+
28+
29+
There's two ways to tell the compiler what the type should be
30+
when the compiler cannot figure it out.
31+
32+
The first way is to add a type annotation (usually after wrapping
33+
the expression in parenthesis). This is annoying to do because
34+
of the added parenthesis, two colons, and in some cases the need to
35+
fully specify all the types of the function or value. -}
36+
37+
usage_inputType :: Int
38+
usage_inputType = (polymorphicCode :: Array String -> Int) []
39+
40+
usage_elemType :: Int
41+
usage_elemType = polymorphicCode ([] :: Array String)
42+
{-
43+
The second way is using "visible type applications".
44+
45+
Using `forall someType. someType -> Int` as an example, the
46+
`forall someType.` part is really a function. We could read the above as
47+
"Given an argument that is a type (e.g. `String`) rather than a value
48+
(e.g. "foo"), I will return to you a function that takes a value of that type
49+
and produce a value of type `Int`."
50+
51+
"Visible Type Applications" are called thus because these type arguments
52+
are applied to these kinds of functions, but these applications that were
53+
previously invisible to the user are now made visible. Put differently,
54+
the compiler would automatically apply these type arguments but without the
55+
user's knowledge or input. Now, however, the user can also apply these type arguments.
56+
57+
Visible Type Applications (or VTAs for short) are opt-in syntax.
58+
They only work if one writes their `forall` part a specific way
59+
by adding a `@` character in front of the type variable name
60+
(e.g. `someType` becomes `@someType`).
61+
62+
Rewriting `polymorphicCode` to use this opt-in syntax, we get: -}
63+
64+
polymorphicCode2 :: forall @pleaseInferThisType. pleaseInferThisType -> Int
65+
polymorphicCode2 _someValue = 1
66+
67+
-- And now we can use it by applying the type `String` to that type variable.
68+
-- We apply the type by putting a `@` character in front of the type name.
69+
usage2_example :: Int
70+
usage2_example = polymorphicCode2 @String "bar"
71+
72+
-- In our original case of using a higher-kinded type (e.g. `Array Int`),
73+
-- we need to wrap the type in parenthesis.
74+
75+
usage2_inputType :: Int
76+
usage2_inputType = polymorphicCode2 @(Array String) []
77+
78+
-- Since `[]`'s inferred type is `forall a. Array a` rather than `forall @a. Array a`,
79+
-- we cannot use VTAs to determine the element type.
80+
-- This code is commented out because we'll get a compiler error.
81+
-- usage2_elemType :: Int
82+
-- usage2_elemType = polymorphicCode2 ([] @String))
83+
84+
-- Lastly, if we opt-in to this VTA syntax, we must either use it or not use it doesn't mean we have to use VTAs
85+
-- to make the function work. The below code is valid
86+
87+
usage3 :: Int
88+
usage3 = polymorphicCode2 true
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
module Syntax.Basic.VisibleTypeApplications.OrderMatters where
2+
3+
-- When we write the following function...
4+
basicFunction :: Int -> String -> Boolean -> String
5+
basicFunction _i _s _b = "returned value"
6+
7+
-- ... we know that the order of the arguments matters.
8+
-- The below usage is valid
9+
usage :: String
10+
usage = basicFunction 1 "foo" false
11+
12+
-- whereas this one is not because the first argument must be an `Int`
13+
-- usage2 :: String
14+
-- usage2 = basicFunction "foo" 1 false
15+
16+
-- Similarly, because functions are curried,
17+
-- when we apply just one argument, we get back a function
18+
-- that takes the remaining arguments
19+
20+
basicFunction' :: String -> Boolean -> String
21+
basicFunction' = basicFunction 1
22+
23+
-- These same ideas apply to VTAs. Notice below that VTA support is only added
24+
-- to the second and fourth type variable.
25+
vtaFunction
26+
:: forall first @second third @fourth
27+
. first
28+
-> second
29+
-> third
30+
-> fourth
31+
-> String
32+
vtaFunction _first _second _third _fourth = "returned value"
33+
34+
-- Type-level arguments (e.g. VTAs) are always applied before value-level arguments.
35+
-- Why? Because those arguments appear earlier in the function.
36+
-- If we want to use VTAs to specify which types `second` and `fourth` are,
37+
-- we must apply those type arguments BEFORE applying any value arguments. In other words,
38+
-- the below code is correct:
39+
40+
usage3 :: String
41+
usage3 = vtaFunction @Int @Int "first" 2 "third" 4
42+
43+
-- whereas this code would be incorrect:
44+
-- usage3 :: String
45+
-- usage3 = vtaFunction "first" @Int 2 "third" @Int 4
46+
47+
-- Put differently, we can define a new function by only applying a single type argument.
48+
49+
vtaFunction'
50+
:: forall first third fourth
51+
. first
52+
-> Int
53+
-> third
54+
-> fourth
55+
-> String
56+
vtaFunction' = vtaFunction @Int -- force `second` to be `Int`
57+
58+
-- Or by type-applying multiple arguments
59+
vtaFunction''
60+
:: forall first third
61+
. first
62+
-> Int
63+
-> third
64+
-> Int
65+
-> String
66+
vtaFunction'' = vtaFunction @Int @Int -- force `second` and `fourth` to be `Int`
67+
68+
-- Note: the astute reader will have noticed that the `@` characters don't appear in
69+
-- `vtaFunction'` and `vtaFunction''`. Since this is opt-in syntax, one must
70+
-- opt-in every time a new function is defined, even if that function
71+
-- is derived from applying one argument to a multi-argument curried function.

0 commit comments

Comments
 (0)