Skip to content

Commit

Permalink
Merge pull request #130 from JordanMartinez/development
Browse files Browse the repository at this point in the history
Make next release: ps-0.12.x-v0.9.4
  • Loading branch information
JordanMartinez committed Nov 12, 2018
2 parents a244aee + 8f5dc5e commit 6a6c028
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 8 deletions.
6 changes: 5 additions & 1 deletion 00-Getting-Started/01-Install-Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@

Throughout your learning process, it will be helpful to ask others for help. The two places this is often done is on the ML forum and the Slack group chat. If you encounter problems when installing anything below, ask for help on the Slack group's `#purescript-beginner` channel and you should receive help.

- Register for an account on the Functional Programming Slack group [here](https://functionalprogramming.slack.com/) and add yourself to these two channels:`#purescript-beginner`, `#purescript`. You may also be interested in these channels: `#categoryTheory`, `#haskell`, and `#haskell-beginner` .
- Register for an account on the Functional Programming Slack group [here](https://fpchat-invite.herokuapp.com/) and add yourself to these two channels:`#purescript-beginner`, `#purescript`. You may also be interested in these channels: `#categoryTheory`, `#haskell`, and `#haskell-beginner` .
- Register for the Purescript ML forum [here](https://discourse.purescript.org/)

## PureScript's Open Collective

If you ever want to support PureScript, consider making a pledge on its [Open Collective](https://opencollective.com/purescript) page.

## Setting up Purescript for the First Time

### Installation
Expand Down
6 changes: 6 additions & 0 deletions 00-Getting-Started/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ TODO, but the general idea:

### ...but not write Javascript to build it...

The benefits of strong types:
- Types == UML diagrams
- The types guide how something should be implemented
- The compiler can infer runtime code
- Certain classes of bugs are eliminated

TODO, but the general idea is:
- dynamic typing -> runtime errors
- a linter is just a basic static type checker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ A type-level function can only "compute" a type-level expression when the types
To understand unification at a deeper level, see these links:
- [Type Checking](https://www.youtube.com/watch?v=r030JkmMLMI). This video **quickly** explains some of the notation used in the paper below, but not all of it.
- [Introduction to Type Inference](https://www.youtube.com/watch?v=il3gD7XMdmA). This video will explain a few more pieces of the notation used in the paper below as well as the problems that arise in type inference. Unfortunately, the teacher goes through concepts quickly and runs out of time, so not everything is immediately understandable through the first viewing.
- [Phil's overview of the Purescript Type's System](https://www.youtube.com/embed/SPpIbiZFPRY?start=2258), where he shows how the compiler unifies types using the same notation above.
- [The original paper describing instance chains](http://web.cecs.pdx.edu/~mpj/pubs/instancechains.pdf).

## Functional Dependencies Reexamined
Expand Down
32 changes: 28 additions & 4 deletions 21-Hello-World/01-FP-Philosophical-Foundations/05-Type-Classes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
# Type Classes

Type classes abstract general concepts into an "interface" that can be implemented by various data types. They are usually an encapsulation of 1-4 things:
## A Short Intro to Category Theory

In short, type classes are usually "encodings" of various concepts from Category Theory. Category Theory (herafter referred to as 'CT') is all about functions and their compositions. Fortunately, a programmer often has an easier time understanding CT than a mathematician. Why? AFAIK, a mathematician learning CT feels something like this:

> A programmer is told to write the implementation for a function. When shown the function, he sees a type signature, `QLD -> M42X`. He asks his boss, "What are the instances of the `QLD` type!? What are the instances of the `M42X` type!?" His boss replies, "You cannot know, nor will you ever know. Now get to work." Terrified, he tries writing something and hopes the compiler will issue a warning that gives him a hint." After compilining, the console mockingly reads, "Error. Try again." How does he implement the function?
The issue described above is that a mathematician cannot "peek" through the type to see what its instances are whereas a programmer can. Once a programmer knows that `QLD` is a type alias for `Apple`, whose only instance is `Apple` and `M42X` is a type alias for `String`, a programmer knows that the function is as simple as writing `functionName Apple = "Apple"`:

```purescript
data Apple = Apple
type QLD = Apple
type M42X = String
functionName :: QLD -> M42X
functionName Apple = "Apple"
```

## Type Classes As Category Theory Terms

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

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

1. (Almost Always) The definition of type signatures for a single/multiple functions/values.
- Functions may be put into infix notation using aliases to make it easier to write them.
Expand All @@ -9,11 +30,14 @@ Type classes abstract general concepts into an "interface" that can be implement
- They also help one to know how to refactor code. Given `left-hand-side == right-hand-side`, evaluating code on the left may be more expensive (memory, time, IO, etc.) than the code on the right.
3. (Frequently) The functions/values that can be derived once one implements the type class.
- Most of the power/flexibility of type classes come from the combination of the main functions/values implemented in a type class' definition and these derived functions. When a type class extends another, the type class' power increases, its flexibility decreases, and its costs increase.
- For example, `Apply` is a less powerful typeclass than Monad because it does not have `bind` but is more flexible than Monad because it can compute things in parallel.
- For example, `Apply` is a less powerful typeclass than `Monad` because it does not have `bind` but is more flexible than `Monad` because it can compute things in parallel.
4. (Sometimes) Something that combines multiple type classes together into one.

Here are some examples:
- The `Show` typeclass specifies a type signature for a function called `show`, but implementations don't have any laws for it, nor are there any derived functions.
While it is possible for a programmer to define a type class without laws, there is a debate about whether this is a good decision. Most say classes should always have laws (i.e. be a term from Category Theory) whereas others say laws should not always be required because it enables reusing the same function name for the same concept (i.e. be 'just' an interface). The counterargument to this last point is that one usually hasn't thought through their design that deeply yet. A Reddit thread discusses some of the tradeoffs of each approach here: https://www.reddit.com/r/haskell/comments/5gospp/dont_use_typeclasses_to_define_default_values/

## Examples

Here are some examples that demonstrate the combination of the 1-4 elements from above:
- The `Eq` type class specifies a type signature for a function called `eq` and `notEq`, and laws for the two, but there are not any derived functions.
- The `Ord` type class is similar to `Eq`, but it does have derived functions.

Expand Down
47 changes: 44 additions & 3 deletions 21-Hello-World/04-Debugging/src/01-General-Debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ The following sections are tips for debugging issues that may arise in a strongl

## Type Directed Search

Otherwise known as "typed holes."

If you recall in `Syntax/Basic Syntax/src/Data-and-Functions/Type-Directed-Search.md`, we can use type-directed search to
1. help us determine what an entity's type is
2. guide us in how to implement something
Expand Down Expand Up @@ -38,15 +40,16 @@ If you encounter a problem or need help, this should be one of the first things

## Getting the Type of an Expression from the Compiler

This tip comes from cvlad on the Slack channel (I've edited his response below for clarity):
> If you want the type of `something`, a good trick is to assert its type to something random like `Unit`. For example, you could write: `(log "hola") :: Unit`. The compiler will give you an error such as, "Cannot unify `Unit` with `_`", where `_` will be the type of the expression.
This is known as "typed wildcards".

In a function body, wrapping some term with `(term :: _)` will cause the compiler to infer the type for you.

```purescript
main :: Effect Unit
main = do
a <- computeA
b <- computeB
c <- (\a -> (\c -> ((doX c) :: Unit)) <$> box a) <$> (Box 5) <*> (Box 8)
c <- (\w x -> ((doX x) :: _)) <$> box a) <$> (Box 5) <*> (Box 8)
```

## Getting the Type of a Function from the Compiler
Expand All @@ -62,3 +65,41 @@ In such cases, we can completely omit the type signature and the compiler will u
-- stating what its inferred type is
f = (\a -> (\c -> doX c) <$> box a) <$> (Box 5) <*> (Box 8)
```

However, the above is not always useful when one only wants to know what the type of either an argument or the return type. In such situations, one can use typed wildcards from above in the type signature:
```purescript
doesX :: String -> _ -> Int
doesX str anotherString = length (concat str anotherString)
```

## Determining why a type was inferred incorrectly

Sometimes, I wish we could have a 'unification trace' or a 'type inference trace'. I know the code I wrote works, but there's some mistake somewhere in my code that's making the compiler infer the wrong type at point X, which then produces the type inference problem much later at point Y. To solve Y, I need to fix the problem X, but I'm not sure where X is.

Here's an example:
```purescript
type Rec = { a :: String }
f :: String -> String
f theString = wrap (unwrap theString)
where
wrap :: String -> Rec
wrap theString = { a: theString }
{-
the mistake! Compiler says
Cannot match type
{ a :: String }
with type
{ a :: String, b :: String }
unwrap :: Rec -> String
unwrap rec = rec.b
```

From the Slack channel, garyb mentioned passing the `--verbose-errors` flag to the compiler. **This will output a LOT of information**, but it's that or nothing. To do that, run this code:

```bash
pulp --psc-package build -- --verbose-errors
pulp --psc-package build -- -v
```
2 changes: 2 additions & 0 deletions 21-Hello-World/05-Testing/test/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ On another hand, to successfully prove that `reverse` works as expected, one wou

Usually, people who have never heard of property testing will think it is a "silver bullet" when it comes to writing tests. However, property testing can only cover a select number of tests cases before one must resort to unit testing. Rather than explaining it here, see [this article](https://fsharpforfunandprofit.com/posts/property-based-testing-2/) that demonstrates 7 situations where property testing works. If a test falls outside of that pattern, one will likely need to use unit testing instead.

Still, before deciding that one must use unit tests, consider using [state machine testing](http://qfpl.io/posts/intro-to-state-machine-testing-1/)

## Conclusion

As much as possible, use Property Testing. When that does not suffice, one must resort back to unit testing.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Limitations of Free

In this video, John De Goes explains what some of the limitations of the Free monad are...
- parallelism
- racing
- alternatives
- e.g. stuff one can't model using just the Monad structure of Free

... and how one can 'hack' those into it. A non-hacky solution is possible, but writing in such a 'language' would likely require a new programming language entirely.

https://www.youtube.com/watch?v=A-lmrvsUi2Y
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Other Approaches

This page lists other ways to structure one's code. It's content is not well-refined or well-presented but merely lists other things to know about.

- [Capability vs Suitability](https://www.parsonsmatt.org/2018/11/03/capability_and_suitability.html)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Using Variant-Based Errors

See [The Problem with Typed Errors](https://www.parsonsmatt.org/2018/11/03/trouble_with_typed_errors.html)
4 changes: 4 additions & 0 deletions 31-Design-Patterns/02-Partial-Functions/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ There are three different ways one can handle partial functions in Purescript:
## Compilation Instruction

Start the REPL, import the file's module, and pass in different arguments to the function to see what happens

## Other Useful Links

- [Lamda The Ultimate - Pattern Factory](https://github.com/thma/LtuPatternFactory/tree/master) - Explains FP design patterns using OO terms.
5 changes: 5 additions & 0 deletions 31-Design-Patterns/14-Cursors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Cursors

See this [post](https://cs-syd.eu/posts/2018-10-28-cursor-list) that clearly explains the problem and solution it solves.

Then, see my conclusion to an exploration of defining a cursor-based data structure that supports multiple carets/selections [here](https://gist.github.com/JordanMartinez/526c5b09b33ffe97932d7990b0470043#file-multi-caret-selection-textcontent-purs-L381) with the full exploration [here](https://gist.github.com/JordanMartinez/526c5b09b33ffe97932d7990b0470043)
3 changes: 3 additions & 0 deletions 41-Ecosystem/Type-Classes/Group-Like.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Group-Like

[This image](https://www.wikiwand.com/en/Semigroup#/Generalizations) summarizes how the various group-related type classes relate.

0 comments on commit 6a6c028

Please sign in to comment.