-
Notifications
You must be signed in to change notification settings - Fork 91
Expand on documentation #217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
9464e86
276a5e5
c48a6e6
e7de566
da12208
7f4e169
8157482
285f934
0b62cf3
6587f19
bf1a5b4
0fb3e86
0bfaad0
ec6710f
2224347
5ab4e52
07bef30
8d79a6b
24f4ca7
d939da5
b424064
a608415
105a53e
85039e8
6e14a53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -63,6 +63,17 @@ infixr 1 bindFlipped as =<< | |
| instance bindFn :: Bind ((->) r) where | ||
| bind m f x = f (m x) x | ||
|
|
||
| -- | The `Array` monad works like a nested for loop. Each | ||
| -- | `bind`/`>>=` adds another level of nesting in the loop: | ||
| -- | ``` | ||
| -- | foo :: Array Int | ||
| -- | foo = do | ||
|
||
| -- | ["a", "b"] >>= \eachElementInArray1 -> | ||
| -- | ["c", "d"] >>= \eachElementInArray2 | ||
| -- | pure (eachElementInArray1 <> eachElementInArray2) | ||
| -- | | ||
| -- | foo == [ ("a" <> "c"), ("a" <> "d"), ("b" <> "c"), ("b" <> "d") == [ "ac", "ad", "bc", "bd"] | ||
|
||
| -- | ``` | ||
| instance bindArray :: Bind Array where | ||
| bind = arrayBind | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,20 @@ import Type.Data.RowList (RLProxy(..)) | |
| -- | `Monoid`s are commonly used as the result of fold operations, where | ||
| -- | `<>` is used to combine individual results, and `mempty` gives the result | ||
| -- | of folding an empty collection of elements. | ||
| -- | | ||
| -- | ### Newtypes for Monoid | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should save the specifics of each Monoid-related newtype to the definitions of the newtypes themselves. I suspect it be easier for people to understand these if they can see the rendered definitions alongside the documentation which says how they work, and also this would be very easy to get out of sync since the newtypes themselves live in separate files. I do think this is a good place to mention the issue that some types permit multiple Monoid instances, and that we can express this with newtypes, but I think it would be best to keep that discussion minimal here. Something like "For example, the Additive newtype has a Monoid instance which is based on Semiring's Also, I realise this is a bit of a nitpick, but I would also prefer not to call it a "workaround", because I think doing this means admitting that not being able to equip a type with two Monoid instances is a deficiency (I don't think it is).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Agreed. Does my rendering work? Or are there other changes you would prefer?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks great 👍 |
||
| -- | | ||
| -- | Some types (e.g. `Int`, `Boolean`) can implement multiple law-abiding | ||
| -- | instances for `Monoid`. For example, `<>` could be `+` and `mempty` could | ||
| -- | be `0`. Likewise, `<>` could be `*` and `mempty` could be `1`. | ||
|
||
| -- | To workaround these ambiguous situations, one should use newtypes | ||
| -- | to specify which instance should be used: | ||
| -- | - `Additive`: use `Semiring`'s `plus`/`+` and `zero` for `<>` and `mempty`. | ||
| -- | - `Multiplicative`: use `Semiring`'s `mul`/`*` and `one` for `<>` and `mempty`. | ||
| -- | - `Conj`: use `HeytingAlgebra`'s `conj`/`&&` and `tt` for `<>` and `mempty`. | ||
| -- | - `Disj`: use `HeytingAlgebra`'s `disj`/`||` and `ff` for `<>` and `mempty`. | ||
| -- | - `Endo`: use `Category`'s `compose`/`<<<` and `identity` for `<>` and `mempty`. | ||
| -- | - `Dual`: use `Category`'s `composeFlipped`/`>>>` and `identity` for `<>` and `mempty`. | ||
| class Semigroup m <= Monoid m where | ||
| mempty :: m | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,16 @@ import Type.Data.RowList (RLProxy(..)) | |
| -- | - Associativity: `(x <> y) <> z = x <> (y <> z)` | ||
| -- | | ||
| -- | One example of a `Semigroup` is `String`, with `(<>)` defined as string | ||
| -- | concatenation. | ||
| -- | concatenation. Another example is `List a`, with `(<>)` defined as | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is definitely a good example to include here 👍 |
||
| -- | list concatenation. | ||
| -- | | ||
| -- | ### Newtypes for Semigroup | ||
| -- | | ||
| -- | There are two other ways to implement an instance for this type class | ||
| -- | regardless of which type is used. These instances can be used by | ||
| -- | wrapping the values in one of the two newtypes below: | ||
| -- | 1. `First` - Use the first argument every time: `append first _ = first`. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These instances are a bit weird and somewhat rarely used, so I'm not sure they deserve a mention here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would say they deserve a mention because it mirrors what is said in
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just think that of all the things we might want to say about semigroups to someone encountering the concept for the first time, I think the First and Last semigroups should be fairly low down on the list, even if their newtypes do happen to live in this repository. While having some level of understanding of the Semigroup type class is more or less required if you want to use PureScript, I would argue that the First and Last semigroups are very much not required. I think it’s more respectful of the user’s time and energy to avoid mentioning things if we don’t expect that they will find them useful at the moment they are reading the docs in question.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then again, they are simple examples, and giving plenty of simple examples is always an important part of teaching these concepts, so maybe they do deserve a mention here. |
||
| -- | 2. `Last` - Use the last argument every time: `append _ last = last`. | ||
| class Semigroup a where | ||
| append :: a -> a -> a | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,11 +2,23 @@ module Data.Void (Void, absurd) where | |
|
|
||
| import Data.Show (class Show) | ||
|
|
||
| -- | An uninhabited data type. | ||
| -- | An uninhabited data type. In other words, one can never create | ||
| -- | a runtime value of type `Void` becaue no such value exists. | ||
| -- | | ||
| -- | `Void` is useful to eliminate the possibility of a value being created. | ||
| -- | For example, a value of type `Either Void Boolean` can never have | ||
| -- | a Left value created in PureScript. | ||
| -- | | ||
| -- | This should not be confused with the word, `void,` that commonly appears in | ||
|
||
| -- | C-deriving languages, such as Java: | ||
|
||
| -- | ``` | ||
| -- | public class Foo { | ||
| -- | void doSomething() { System.out.println("hello world!"); } | ||
| -- | } | ||
| -- | ``` | ||
| -- | | ||
| -- | In PureScript, one often uses `Unit` to achieve similar effects as | ||
| -- | the lowercased `void` above. | ||
|
||
| newtype Void = Void Void | ||
|
|
||
| instance showVoid :: Show Void where | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, just to clarify what I was trying to get at before: I think it's best to provide a precise explanation which says what the thing does before trying to build intuition. In this case I think we should follow the lead of the docs in Data.Array.concatMap to start with before mentioning the similarity to a nested for loop. Perhaps:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. I'll use that rendering.