-
Notifications
You must be signed in to change notification settings - Fork 73
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 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
- Loading branch information
1 parent
c140536
commit 749e370
Showing
40 changed files
with
1,098 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,7 +48,7 @@ Unlike the manual install, `nvm` properly handles the npm prefix for you. So, yo | |
Once you have installed `npm`, we can use it to install everything in one command: | ||
|
||
```sh | ||
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] | ||
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] | ||
``` | ||
|
||
|
||
|
@@ -63,9 +63,9 @@ npm i -g purs-backend-es | |
The following commands should now work: | ||
|
||
```sh | ||
purs --version # 0.15.7 | ||
spago --version # 0.20.9 | ||
esbuild --version # 0.15.7 | ||
purs --version # 0.15.13 | ||
spago --version # 0.21.0 | ||
esbuild --version # 0.19.8 | ||
``` | ||
|
||
### Building This Project | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,11 @@ This folder accomplishes the following: | |
|
||
## History: How We Got Here | ||
|
||
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. | ||
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. 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`. | ||
|
||
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`. | ||
|
||
### Phase 1: Initial Tooling | ||
|
||
|
@@ -24,6 +28,8 @@ Bodil Stokke (with later contributions from Harry Garrood) later wrote a tool ca | |
- publish libraries and their docs | ||
- easily bump the project's version | ||
|
||
This is why most of the "core" libraries (PureScript libraries stored under the `purescript` GitHub organization) still have `bower.json` files as their dependencies. | ||
|
||
### Phase 2: The `psc-package` Experiment | ||
|
||
`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: | |
|
||
### Phase 3: Improving the `psc-package` Developer Workflow via `Spago` | ||
|
||
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`. | ||
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`. | ||
|
||
The below image summarizes the current state: | ||
|
||
![Build Tool Relationships "Build Tool Relationships"](./assets/Build-Tool-Relationships--With-Spago.svg) | ||
|
||
### Phase 4: `Spago` becomes mainstream while `psc-package` is less used | ||
|
||
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. | ||
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. | ||
|
||
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: | ||
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: | ||
- publish their library's docs to Pursuit | ||
- include their library in a package set, so `spago` users can use it | ||
|
||
### Phase 5: The need for a PureScript registry (Bower registry no longer accepts new uploads) | ||
|
||
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. | ||
|
||
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. | ||
|
||
Regardless, the following is still true: | ||
- most people are now using `spago` | ||
- the `pulp` + `bower` workflow is still needed to publish a library, but it works differently now. | ||
- 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) | ||
- See the `Dependency Managers/Bower Explained` file for clarification on how to install packages as dependencies if one is using `bower` | ||
- Thomas has written a [Recommended Tooling for PureScript Applications](https://discourse.purescript.org/t/recommended-tooling-for-purescript-applications-in-2019/948) post. | ||
|
||
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. | ||
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. | ||
|
||
### Phase 6: Updating JavaScript output to ES modules and delegating bundling to 3rd-party tools | ||
|
||
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. | ||
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. | ||
|
||
See the [0.15.0 Migration Guide](https://github.com/purescript/documentation/blob/master/migration-guides/0.15-Migration-Guide.md) for more details. | ||
|
||
|
@@ -81,15 +78,29 @@ While the Purescript compiler produces correct JavaScript code, there were a num | |
|
||
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). | ||
|
||
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. | ||
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. | ||
|
||
### Phase 8: The Registry and the Spago Rewrite | ||
|
||
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. | ||
|
||
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`. | ||
|
||
## Spago: Haskell Legacy codebase or PureScript rewrite codebase? | ||
|
||
| Type | NPM Package | Versions | Install via | Alternative | | ||
| - | - | - | - | - | | ||
| Legacy Spago | `spago` | `0.0.1` - `0.21.0` | `npm i spago` | `npm i spago-legacy` (installs `[email protected]` under binary name `spago-legacy`) | | ||
| Rewrite Spago | `spago` | `0.92.0` - `0.93.x` | `npm i spago@next` | - | | ||
|
||
## Overview of Tools | ||
|
||
| Name | Type/Usage | Comments | URL | | ||
| - | - | - | - | | ||
| purs | PureScript Compiler | Used to be called `psc` | -- | | ||
| spago | Build Tool | Front-end to `purs` and `package-set`-based projects | https://github.com/purescript/spago | ||
| pulp | Build Tool | Front-end to `purs`. Builds & publishes projects | https://github.com/purescript-contrib/pulp | | ||
| spago (rewrite) | Build Tool | Front-end to `purs`; `package-set`-based or dependency-range -based projects | https://github.com/purescript/spago | | ||
| spago (legacy) | Build Tool | Front-end to `purs` and `package-set`-based projects | https://github.com/purescript/spago-legacy | ||
| pulp | Build Tool | Front-end to `purs`. Builds & publishes projects (being deprecated) | https://github.com/purescript-contrib/pulp | | ||
| bower | Dependency Manager (being deprecated) | -- | https://bower.io/ | | ||
| purs-tidy | PureScript Formatter | -- | https://github.com/natefaubion/purescript-tidy | ||
| purs-backend-es | Produces optimized JavaScript from PureScript | Only intended for production-level usage | https://github.com/aristanetworks/purescript-backend-optimizer | ||
|
88 changes: 88 additions & 0 deletions
88
11-Syntax/01-Basic-Syntax/src/16-Visible-Type-Applications/01-Intro.purs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
module Syntax.Basic.VisibleTypeApplications.Intro where | ||
{- | ||
Visible Type Applications is a feature that only works completely | ||
as of PureScript 0.15.13. While it was supported earlier than that, | ||
there were a few bugs that hindered its usage. The content in this file | ||
and those that follow in this folder assume one is using PureScript 0.15.13. | ||
Sometimes, using polymorphic code can be annoying | ||
because the compiler cannot infer what type you want to use. -} | ||
|
||
polymorphicCode :: forall pleaseInferThisType. pleaseInferThisType -> Int | ||
polymorphicCode _someValue = 1 | ||
{- | ||
problematicUsage :: Int | ||
problematicUsage = polymorphicCode [] | ||
The above code is commented out because it will produce a compiler error. | ||
The empty array is inferred by the compiler to have the type, | ||
`forall a. Array a`. Because there are no elements within the | ||
array, the compiler has no idea what the element type is. So, it infers it | ||
to the most generic type it can be: `forall a. a`. | ||
In this situation, we would need to tell the compiler what that type is | ||
by doing one of two things: | ||
- indicating what the input type of `polymorphicCode` is | ||
- indicating what the element type of the empty array is | ||
There's two ways to tell the compiler what the type should be | ||
when the compiler cannot figure it out. | ||
The first way is to add a type annotation (usually after wrapping | ||
the expression in parenthesis). This is annoying to do because | ||
of the added parenthesis, two colons, and in some cases the need to | ||
fully specify all the types of the function or value. -} | ||
|
||
usage_inputType :: Int | ||
usage_inputType = (polymorphicCode :: Array String -> Int) [] | ||
|
||
usage_elemType :: Int | ||
usage_elemType = polymorphicCode ([] :: Array String) | ||
{- | ||
The second way is using "visible type applications". | ||
Using `forall someType. someType -> Int` as an example, the | ||
`forall someType.` part is really a function. We could read the above as | ||
"Given an argument that is a type (e.g. `String`) rather than a value | ||
(e.g. "foo"), I will return to you a function that takes a value of that type | ||
and produce a value of type `Int`." | ||
"Visible Type Applications" are called thus because these type arguments | ||
are applied to these kinds of functions, but these applications that were | ||
previously invisible to the user are now made visible. Put differently, | ||
the compiler would automatically apply these type arguments but without the | ||
user's knowledge or input. Now, however, the user can also apply these type arguments. | ||
Visible Type Applications (or VTAs for short) are opt-in syntax. | ||
They only work if one writes their `forall` part a specific way | ||
by adding a `@` character in front of the type variable name | ||
(e.g. `someType` becomes `@someType`). | ||
Rewriting `polymorphicCode` to use this opt-in syntax, we get: -} | ||
|
||
polymorphicCode2 :: forall @pleaseInferThisType. pleaseInferThisType -> Int | ||
polymorphicCode2 _someValue = 1 | ||
|
||
-- And now we can use it by applying the type `String` to that type variable. | ||
-- We apply the type by putting a `@` character in front of the type name. | ||
usage2_example :: Int | ||
usage2_example = polymorphicCode2 @String "bar" | ||
|
||
-- In our original case of using a higher-kinded type (e.g. `Array Int`), | ||
-- we need to wrap the type in parenthesis. | ||
|
||
usage2_inputType :: Int | ||
usage2_inputType = polymorphicCode2 @(Array String) [] | ||
|
||
-- Since `[]`'s inferred type is `forall a. Array a` rather than `forall @a. Array a`, | ||
-- we cannot use VTAs to determine the element type. | ||
-- This code is commented out because we'll get a compiler error. | ||
-- usage2_elemType :: Int | ||
-- usage2_elemType = polymorphicCode2 ([] @String)) | ||
|
||
-- 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 | ||
-- to make the function work. The below code is valid | ||
|
||
usage3 :: Int | ||
usage3 = polymorphicCode2 true |
71 changes: 71 additions & 0 deletions
71
11-Syntax/01-Basic-Syntax/src/16-Visible-Type-Applications/02-Order-Matters.purs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
module Syntax.Basic.VisibleTypeApplications.OrderMatters where | ||
|
||
-- When we write the following function... | ||
basicFunction :: Int -> String -> Boolean -> String | ||
basicFunction _i _s _b = "returned value" | ||
|
||
-- ... we know that the order of the arguments matters. | ||
-- The below usage is valid | ||
usage :: String | ||
usage = basicFunction 1 "foo" false | ||
|
||
-- whereas this one is not because the first argument must be an `Int` | ||
-- usage2 :: String | ||
-- usage2 = basicFunction "foo" 1 false | ||
|
||
-- Similarly, because functions are curried, | ||
-- when we apply just one argument, we get back a function | ||
-- that takes the remaining arguments | ||
|
||
basicFunction' :: String -> Boolean -> String | ||
basicFunction' = basicFunction 1 | ||
|
||
-- These same ideas apply to VTAs. Notice below that VTA support is only added | ||
-- to the second and fourth type variable. | ||
vtaFunction | ||
:: forall first @second third @fourth | ||
. first | ||
-> second | ||
-> third | ||
-> fourth | ||
-> String | ||
vtaFunction _first _second _third _fourth = "returned value" | ||
|
||
-- Type-level arguments (e.g. VTAs) are always applied before value-level arguments. | ||
-- Why? Because those arguments appear earlier in the function. | ||
-- If we want to use VTAs to specify which types `second` and `fourth` are, | ||
-- we must apply those type arguments BEFORE applying any value arguments. In other words, | ||
-- the below code is correct: | ||
|
||
usage3 :: String | ||
usage3 = vtaFunction @Int @Int "first" 2 "third" 4 | ||
|
||
-- whereas this code would be incorrect: | ||
-- usage3 :: String | ||
-- usage3 = vtaFunction "first" @Int 2 "third" @Int 4 | ||
|
||
-- Put differently, we can define a new function by only applying a single type argument. | ||
|
||
vtaFunction' | ||
:: forall first third fourth | ||
. first | ||
-> Int | ||
-> third | ||
-> fourth | ||
-> String | ||
vtaFunction' = vtaFunction @Int -- force `second` to be `Int` | ||
|
||
-- Or by type-applying multiple arguments | ||
vtaFunction'' | ||
:: forall first third | ||
. first | ||
-> Int | ||
-> third | ||
-> Int | ||
-> String | ||
vtaFunction'' = vtaFunction @Int @Int -- force `second` and `fourth` to be `Int` | ||
|
||
-- Note: the astute reader will have noticed that the `@` characters don't appear in | ||
-- `vtaFunction'` and `vtaFunction''`. Since this is opt-in syntax, one must | ||
-- opt-in every time a new function is defined, even if that function | ||
-- is derived from applying one argument to a multi-argument curried function. |
Oops, something went wrong.