Skip to content

Commit

Permalink
Surgery on 0.14 syntax branch (#502)
Browse files Browse the repository at this point in the history
* Relocate 'let lacks generalization' to be after let/where file

* Mention that let bindings can have type signatures

* Cover let..in syntax first; explain that where is syntax sugar for let

* Update let lacks generalization examples to be clearer

* Fix type signature: result is a value, not a function

* Temporarily update Prelude to point to ps-0.14 branch

* Update `spago docs` command to use `spago docs --open`

* Provide examples of values before example of a function

* Add a JavaScript corresponding example to how functions are defined in PS

* Clean up explanations for initial exposure to syntax in PS

* Update Box example to illustrate which parts define the type and value

* Start introducing the concept of explicit kind signatures

* Fix identation of explanation so that it's more readable

* Clean up the type signatures a bit and rename type via emphasis

* Fix typo and provide clearer rendering without mentioning Haskell

* Remove `data`: might incorrectly convey that such types are data types

* Start exposing reader to various ways of writing functions

* Cleanup docs

* Remove unused trailing comment

* Explain that concept is known as 'eta-expansion'

* Update data examples; note situations where kind signatures are required

* Clarify what Type Constructor and Data Constructor mean

* Fix typo

* Replace notion of Type in pattern matching with Data Constructor

* Swap positions: unicode syntax follows keywords and syntax

* Add forall's unicode character: ∀

* Reword explanation of adding forall syntax to front of type signature

* Remove unicode version of forall as it's covered in Unicode file now

* Show that type aliases can also have kind signatures

* Clean up rendering for let..in/where syntax usage

* Indicate the start and end of let blocks and in blocks

* Rerender type signature phrase using annotation rather than association

* Make monomorphism and polymorphism difference clearer

* Update line numbers in example compiler error example

* Reword indentation explanation to be shorter

* Fix typo

* Capitalize type class to Type Class

* Use commas to separate list

* Add type signatures to remove compiler warnings

* Get rid of compiler warnings in file; fix whitespace issues

* Add whitespace for readability

* Add or remove whitespace for readability

* Fix error in understanding: Boxable still requires an instance

* Bump type class syntax file order by one to make room for new file

* Document that type classes can have kind signatures and provide examples

* Remove some whitespace

* Prevent types from being higher-kinded so as to prevent compiler warnings

* Update FD examples to include variants with kind signatures

* Add kind signatures to prevent compiler warnings

* Indicate that newtypes can have kind signatures, too

* Fix compiler warning: shadowed definition, `Type`, from Prim

* Add kind signatures to prevent compiler warnings

* Remove unneeded import

* Add kind signature to "needed to compile" code

* Briefly cover row kinds so that kind signature for empty row makes sense

- This kind signature is required. Otherwise, we need to write `forall 
kind. kind -> Row kind` as its kind signature.

* Use 'label, rather than 'field' when referring to name part of row

* Fix typo: constraint -> constrain

* Update function abbreviation to use eta-expansion and eta-reduction

* Fix value to types as types to kinds diagram

- This change was made previously, but it looks like it was overwritten 
later, possibly via a bad merge or bad force-push?

* Rephrase: "`kind Type`" -> "kind, `Type`,"

* Update '# Type' to be 'Row Type'

* Indicate that there's only one Proxy type now

* Update examples showing how to create custom kinds

* Use explicit kind signatures rather than (Type :: Kind) syntax

* Add compiler-failing example for data type using coustom kind

* Reorder content

* Add type class example of using custom kind

* Change members to data constructors

* Rename file by dropping the 'Revisited' part

* Update type name: clashing with previous one due to copy and paste

* Comment out Proxy type for now to prevent compiler error

* Bump files twice to make room for two files

* Describe new polykind signature via forall kind

* Explain `Proxy` as a way to pass around type-level values at value-level

* Update type-level functions ReadMe to use kind signature syntax

* Add headers to Unification section to Unification more strongly indicate breaks

* Fix typo due to copy and paste

* Fix generic function to use polymorphic types

* Fix compiler error due to typos

* Change `kind` to something else

- Using `kind` here clashes with the name from `forall kind. kind`

* Update type-level programming examples to use kind signatures

* Show but don't explain reification pattern

* Update conventions; remove ConstrainedToKindName

* Add missing Constraint kind

* Use polykinded Proxy rather than kind-specific Proxy types

* Update module syntax to remove pre 0.14.0 kind imports/exports

* Bump type class gotchas and errors to make room for special classes

* Document special type class: Partial

* Document special type class Coercible (doesn't currently work yet)

* Install safe-coerce

* Import coerce from correct module

* Provide breaking example based on hash being applied to key2 first

* Fix typos

* Fix example illustrating the need for the type role, nominal

* Remove need for type-level programming pre-req for app structure folder

* Remove mention of 'upcoming app structure folder' in type level programming folder

* Fix typo

* Document higher-kinded data, how it works and why use it

* Remove "type classes solve problem of code reuse" and Cat. Theory origin

* Add short explanation of 'scrap your type classes'

* Link to and summarize the Fairbairn Threshold

* Link to 'thinking with types' notes

* Expand and clarify derive newtype & Newtype instance

* Remove PS by Example outdatedness comment in why not learn PS

* Update PS by Example links

* Update Spago: 0.14.0 -> 0.15.2

* Link to minesweeper CLI game

* Link to Boolean Blindness video

* Update overviews of newtypes for Monoid

* Cover Endo monoidal newtype before Dual

* Link to Thomas' answer on why Halogen and comparison to other frameworks

* Link and fully quote Thomas' answer for 'why halogen?'

* Link to debugging tip by kritzcreek

* Update explanation of link: PS book is no longer outdated

* Link to PS Cookbook

* Add more recent link for GADTs/tagless discussion

* Update package-set to latst release; drop ps-0.14 set

* Update `tree` to `tree-rose`

* Make Module Syntax compile again on PS 0.13.x syntax

PS 0.14.x syntax was commented out

* Move ps-0.14.x type-level syntax folder to own temporary folder

* Make Type-Level Syntax compile again on PS 0.13.x

* Remove 'safe-coerce' library from Basic Syntax folder's dependencies

* Move current state of files to 'ps-0.14-syntax' folder

* Get Basic Syntax folder to compile on PS 0.13.x again

* Update PureScript to 0.13.9

* Update spago to 0.16.0

* Update ToC to ps-0.13.x-v0.25.0

* Regenerate changelog

* Do not specify package version; make link always refer to latest release

Note: there are still links that could be updated to use this 'relative' 
link approach. These have not been done here due to lack of time.

* Update ToC to ps-0.13.x-v0.25.0

* Regenerate changelog

* Change PureScript version to 0.13.8

Co-authored-by: Miles Frain <miles.frain@colorado.edu>
Co-authored-by: Răzvan C. Rădulescu <razcore.art@gmail.com>
  • Loading branch information
3 people committed Aug 22, 2020
1 parent 4070f4c commit 7c0ee58
Show file tree
Hide file tree
Showing 123 changed files with 7,057 additions and 1,896 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ before_install:
# ^ Update NPM

install:
- npm i -g purescript@0.13.6 spago@0.14.0
- npm i -g purescript@0.13.8 spago@0.16.0
# ^ Use NPM to install most packages
- chmod +x .travis/spago--print-versions.sh
- ./.travis/spago--print-versions.sh
Expand Down
3 changes: 1 addition & 2 deletions 00-Getting-Started/01-Why-Learn-PureScript.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@ You might want to learn it **now** for these reasons:

You might want to learn it **later** for these reasons:
- PureScript's documentation could be improved in a number of ways:
- `PureScript By Example` is a book written by the creator of the PureScript language that uses a project-oriented approach to get a new learner up to speed quickly. However, the book's code is outdated and still being updated. See `Getting Started/Other Important Info.md` for more details about this update effort.
- Documentation for libraries are good in some areas and lacking in others
- Documentation for libraries are good in some areas and lacking in others.

### How long will it take me before I can write idiomatic code and be productive in PureScript?

Expand Down
8 changes: 4 additions & 4 deletions 00-Getting-Started/02-Install-Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ We can install everything using `npm`. However, getting `npm` is it's own proble

##### Manual Install

Justin Woo explains how to set up one's environment for the `0.12.x` release but has not been updated for two things. First, the PureScript release at the time was `0.12.0` but now `0.13.6` is out. Second, the instructions use `pulp` and `psc-package`, a different build tool workflow than the one we'll use here.
Justin Woo explains how to set up one's environment for the `0.12.x` release but has not been updated for two things. First, the PureScript release at the time was `0.12.0` but now `0.13.8` is out. Second, the instructions use `pulp` and `psc-package`, a different build tool workflow than the one we'll use here.

If you just want to get things set up ASAP, follow the below summary of his article's instructions (using `spago` instead of the other tools). If you want to understand why you should do these commands, read [his article here](https://qiita.com/kimagure/items/570e6f2bbce5b4724564):
1. Install Node 10 or greater: https://nodejs.org/en/download/
Expand All @@ -44,15 +44,15 @@ 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:
```bash
npm i -g purescript@0.13.6 spago@0.14.0 parcel
npm i -g purescript@0.13.8 spago@0.16.0 parcel
```

### Versions Used in this Project

The following commands should now work (the versions beside them are the versions I used when writing this project):
```bash
purs --version # 0.13.6
spago version # 0.14.0
purs --version # 0.13.8
spago version # 0.16.0
parcel --version # 1.12.0
```

Expand Down
10 changes: 3 additions & 7 deletions 00-Getting-Started/04-Other-Important-Info.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
# Other Important Info

[Purescript By Example](https://leanpub.com/purescript/read#) is a book that teaches Purescript. Unfortunately, it is now outdated because it covers Purescript `0.11.7`. The `0.12.0` release included a lot of breaking changes that would require significantly updating the book. However, it's still a useful learning resource.

If you decide to read the book, here are things to be aware of:
- be wary of any references to these [deprecated packages](https://github.com/purescript-deprecated)
- **Refer to [`dwhitney`'s fork of the book's code](https://github.com/dwhitney/purescript-book/tree/0.12)**, which is currently being updating to use `0.13.6`.
- Refer to `Hello-World/Effect-and-Aff/Effect-Eff-and-Aff.md` to understand how to translate the no-longer-used `Eff` type to `Effect` type.
- [Purescript By Example](https://book.purescript.org/) is the official up-to-date book that teaches Purescript.
- [PureScript Cookbook](https://github.com/JordanMartinez/purescript-cookbook) is an unofficial cookbook that shows "How to do X" in PureScript.

## Functional Programming Jargon

Expand Down Expand Up @@ -42,7 +38,7 @@ Then, you use a search query like the following:
- Cons: One does not immediately know which version of a library is displayed, nor what its dependencies are.
- Use the [same instructions used by Hoogle](https://github.com/ndmitchell/hoogle/blob/master/README.md#chrome-integration) to add Pursuit as a search engine to your web browser.
- Read [Pursuit's Search Help page](https://pursuit.purescript.org/help/users#searching)
- Some libraries have not been updated to `0.13.6` and are still on the `0.11.7` release. Some still work; others won't. In this work, we will insure that you do not use any such libraries, but be aware of that if you browse the docs on your own.
- Some libraries have not been updated to `0.13.8` and are still on the `0.11.7` release. Some still work; others won't. In this work, we will insure that you do not use any such libraries, but be aware of that if you browse the docs on your own.
- Lastly, some libraries have not uploaded their latest versions' documentation. In these cases, we will forewarn you. Fortunately, `spago docs` will produce a local version of the source code's documentation that looks similar to Pursuit. It does not support all the features of Pursuit, but it's better than nothing. To do that, follow these commands:
- `spago docs --open` will generate the documentation and then use your default web browser to open the file, `generated-docs/html/index.html`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ data Maybe a
findFirst :: forall a. List a -> (a -> Boolean) -> Maybe a
findFirst Nil condition = Nothing
findFirst' (Cons head tail) condition =
findFirst (Cons head tail) condition =
if (condition head)
then Just head
else findFirst' tail condition
Expand Down
26 changes: 20 additions & 6 deletions 01-FP-Philosophical-Foundations/06-Type-Classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@

## What Problem Do Type Classes Solve?

Code reuse. Rather than writing the same code 25 different times where it differs in only one way each time, we can write code once and "parameterize it" in 25+ different ways.
Their primary use is to make writing some code more convenient / less boilerplatey. Rather than writing the same code 25 different times where it differs in only one way each time, we can write code once and "parameterize it" in 25+ different ways.

To see a bottom-up explanation of this idea, read through the bullet points below and then watch the video.
- This video is a recording of a presentation given by Nathan Faubion, a core contributor to PureScript.
- This video finishes explaining what type classes are around 22:54.
- The parts that follow are more advanced concepts. They explain how to make "real world code" easily testable via type classes and interpreters. You might not understand those explanations until you are more familiar with PureScript syntax.
- The presentation ends at 1:03:58. Nate starts answering people's questions after that.
- Nate's answers to various questions ends at 1:13:12 and the rest of the video are people talking about various PureScript things.
- While Nate explains that type classe enable "code reuse," one could use an approach called "scrap your type classes" (SYTC) to accomplish that goal. SYTC will be covered later in this file.

Video: [Code Reuse in PureScript: Functions, Type Classes, and Interpreters](https://youtu.be/GlUcCPmH8wI?t=24) (actual video title on YouTube: "PS Unscripted - Code Reuse in PS: Fns, Classes, and Interpreters")

## Where Do Type Classes Come From?

Type classes are usually "encodings" of various concepts from Category Theory. Category Theory (hereafter referred to as 'CT') is all about the various ways we can compose functions and do so while adhering to specific laws. It's typically used for control flow (e.g. FP-style "if then else" statements, loops, etc.).
Type classes are usually "encodings" of various concepts from mathematics, specifically abstract algebra and category theory.

Type classes make developers productive. They enable programmers...
- to write 1 line of code that is the equivalent of writing 100s of lines of code.
Expand All @@ -28,7 +30,7 @@ Type classes make developers productive. They enable programmers...

## Type Classes as Encodings of Mathematical Concepts

Putting it differently, if `Some type` can implement some `function(s)/value(s) with a specified type signature` in such a way that the implementation adheres to `specific laws`, one can say it **has** an instance of `some CT concept/term`. Some types cannot satisfy some CT terms' conditions, others can satisfy them in only one way; and still others can satisfy them in multiple ways. Thus, one does not say "`Type X` **is** an instance of [some CT Term]." Rather, one says "`Type X` **has** an instance of [some CT Term]." To see this concept in a clearer way and using pictures, see https://www.youtube.com/watch?v=iJ7V1KXJpsE
Putting it differently, if `Some type` can implement some `function(s)/value(s) with a specified type signature` in such a way that the implementation adheres to `specific laws`, one can say it **has** an instance of the given type class. Some types cannot satisfy a given type class' conditions; others can satisfy them in only one way; and still others can satisfy them in multiple ways. Thus, one does not say "`Type X` **is** an instance of &lt;some type class&gt;." Rather, one says "`Type X` **has** an instance of &lt;some type class&gt;." To see this concept in a clearer way and using pictures, see https://www.youtube.com/watch?v=iJ7V1KXJpsE

Thus, type classes abstract general concepts into an "interface" that can be implemented by various data types. They are usually an encapsulation of 2-3 things:

Expand Down Expand Up @@ -68,9 +70,9 @@ and it uses the alias `<$>` for `map` to enable one to write `function <$> f_a`
- mapFlipped
- flap

## Type Classes and Dual Relationships
## Similarities and Dual Relationships Among Type Classes

Each type class from CT has a corresponding "dual." While there are better ways to explain duals, the basic idea is that the "direction" of the function's arrow gets flipped. When this happens, we usually prefix them with "Co" (e.g. the `product` type's "dual" is the `coproduct` type (i.e. a sum type); the `Monad`'s "dual" is `Comonad`) Likewise, the laws of some type class are the "flipped" version of the laws of its dual.
Some type classes have a corresponding "dual." While there are better ways to explain duals, the basic idea is that the "direction" of the function's arrow gets flipped. When this happens, we usually prefix them with "Co". For example, if we have a type class called `Monad`, the dual of it is called `Comonad`. If `Monad` has laws `A` and `B`, then it's likely that `Comonad` will have laws `A'` and `B'`, which are "flipped" version of `A` and `B`.

For example, a function like `toB` would have its arrow flipped to produce `toA`::

Expand Down Expand Up @@ -144,7 +146,19 @@ Scala uses local instances. Haskell uses global instances and orphan instances a

PureScript uses global instances, and orphan instances are strictly disallowed. Unlike Haskell, there are no "escape hatches." For more context, see [Harry's comment in 'Disallow Orphan Instances' (purescript/purescript#1247)](https://github.com/purescript/purescript/issues/1247#issuecomment-512975645).

## Non-Category Theory Usages of Type Classes
## Scrap Your Type Classes (SYTC)

At the end of the day, mainstream usage of type classes provide a lot of convenience to the developer. Rather than defining a function that takes many arguments, it only takes a few arguments that highlight what you want to do.

As a result, some developers who encounter a problem will immediately decide to use type classes as their solution rather than some other language feature that is more appropriate (e.g. regular functions). For some problems, it is better to use regular functions rather than type classes. Regular functions might be less convenient than type classes, but they can be easier to use in some cases and more performant in others.

To understand the tradeoff, you must
1. understand that [type class constraints are replaced with arguments called 'type class dictionaries'](https://www.schoolofhaskell.com/user/jfischoff/instances-and-dictionaries)
2. realize that the possibly "larger" type class dictionary object argument could be replaced with a "smaller" single function

For more context, see [Scrap Your Type Classes](http://www.haskellforall.com/2012/05/scrap-your-type-classes.html)

## Other Usages of Type Classes

Some type classes are purposefully designed to be lawless because they are used for other situations. Here are some examples:
- Type-level documentation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A way to use specific versions of libraries that are known to compile together w

## Why Use It?

`spago` only allows you to use dependencies that compile together on a specific PureScript release. You do not have to track down which version of a `DependencyA` to use to ensure it compiles when you also use `DependencyB`. Moreover, you don't have to verify that `DependencyA` at `v1.0.0` works on PureScript release `0.13.6` instead of `0.11.7`.
`spago` only allows you to use dependencies that compile together on a specific PureScript release. You do not have to track down which version of a `DependencyA` to use to ensure it compiles when you also use `DependencyB`. Moreover, you don't have to verify that `DependencyA` at `v1.0.0` works on PureScript release `0.13.8` instead of `0.11.7`.

When a new PureScript release with breaking changes occurs, using `bower` is painful until the ecosystem "catches up." Since a new release draws in a lot of people, their initial exploration of PureScript when using `bower` can be horrible.

Expand Down
4 changes: 2 additions & 2 deletions 11-Syntax/01-Basic-Syntax/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ spago build

To see what the documentation looks like, run this command:
```bash
spago docs
spago docs --open
```
Then, open the file, `./generated-docs/index.html`, and open a module to see what it outputs.
The above command will generate the docs, and then open the file, `./generated-docs/index.html`.
11 changes: 11 additions & 0 deletions 11-Syntax/01-Basic-Syntax/ps-0.14-syntax/00-Comments.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Syntax.Basic.Comments where

-- This is a single-line comment
-- Anything past the "--" syntax on a line is regarded as a comment

{-
This is a multi-line comment
Anything between the bracket-dash syntax is regarded as a multi-line comment
-}

{- It can also be used to add a comment in-between stuff -}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
module Syntax.Meta where

-- This file simply shows enough syntax so that the
-- explanation on Kinds (next) makes sense.
--
-- entity_name :: Type Signature
-- entity_name = definition

integer_value :: Int
integer_value = 5

string_value :: String
string_value = "this is text"

-- | In other words...
-- | ```
-- | var one_arg_function = function (argument) {
-- | return bodyThatReturnsType;
-- | };
-- | ```
one_arg_function :: ParameterType -> ReturnType
one_arg_function argument = bodyThatReturnsType

-- Below is an Algebraic Data Type. We'll explain these more later.
--
-- Here, we declare a type called `Type_Used_In_Functions_Type_Signatures`,
-- which has two implementations. The type is used in an entity's
-- Type Signatures while the implementations are used in an entity's
-- definition
data Type_Used_In_Functions_Type_Signatures
= Type_Implementation1
| Type_Implementation2

example1 :: Type_Used_In_Functions_Type_Signatures
example1 = Type_Implementation1

example2 :: Type_Used_In_Functions_Type_Signatures
example2 = Type_Implementation2

-- A "box" that can store only Ints
data Box_That_Stores_Ints = Box Int

example3 :: Box_That_Stores_Ints
example3 = Box 4

example4 :: Int -> Box_That_Stores_Ints
example4 x = Box x

-- A "box" type that can store values of another type.
data Box_That_Stores anotherType = Box_Storing anotherType

example5 :: Box_That_Stores Int
example5 = Box_Storing 4

example6 :: Int -> Box_That_Stores Int
example6 x = Box_Storing x

-- Look! An outer Box that stores an inner Box, that stores an Int
example7 :: Box_That_Stores (Box_That_Stores Int)
example7 = Box_Storing (Box_Storing 4)

-- The "forall someType." syntax will be explained later. It's needed here
-- to make this code compile. You can read example8's type signature as
-- "If you give me a value that has a given type, which I'll refer to as
-- `someType`, then I can give you back a Box that stores a value of
-- `someType`."
example8 :: forall someType. someType -> Box_That_Stores someType
example8 valueWhoseTypeIs_'someType' = Box_Storing valueWhoseTypeIs_'someType'

-- necessary to make this file compile

type ValueType = String
type ParameterType = String
type ParameterType1 = String
type ParameterType2 = String
type ReturnType = String

bodyThatReturnsType :: ReturnType
bodyThatReturnsType = "return value"

bodyOfFunction :: ReturnType
bodyOfFunction = "body of inline function"

0 comments on commit 7c0ee58

Please sign in to comment.