Skip to content

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

Merged
merged 25 commits into from
Sep 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9464e86
Indicate that Array monad is a nested for loop
JordanMartinez May 28, 2020
276a5e5
Expand on Monoid's documentation to explain purpose behind newtypes
JordanMartinez May 29, 2020
c48a6e6
Add another example of `(<>)`: list concatenation
JordanMartinez May 29, 2020
e7de566
Expan on Semigroup's documentation to explain purposes behind newtypes
JordanMartinez May 29, 2020
da12208
Expand on 'uninhabitated data type' meaning for `Void`
JordanMartinez May 29, 2020
7f4e169
Distinguish `Void` from lowercase `void` in C-deriving languages
JordanMartinez May 29, 2020
8157482
Add example of `f <$> arg1 <*> arg2 <*> ... <*> argN` to Apply docs
JordanMartinez May 29, 2020
285f934
Add quick overview of do notation in `Monad` docs
JordanMartinez May 29, 2020
0b62cf3
Add quick overview for ado notation in Applicative
JordanMartinez May 29, 2020
6587f19
Decrease header level to 3 for Monad and Applicative "ado/do notation"
JordanMartinez May 29, 2020
bf1a5b4
Add level 3 header for overview of Monoid/Semigroup newtypes
JordanMartinez May 29, 2020
0fb3e86
Remove do/ado notation explanation in Monad and Applicative
JordanMartinez Jun 4, 2020
0bfaad0
Port Array's "do notation" explanation from Monad to Bind instance
JordanMartinez Jun 4, 2020
ec6710f
Clarify what causes nesting in Array's Bind instance explanation
JordanMartinez Jun 4, 2020
2224347
Do not use do notation for explaining Array's `Bind` instance.
JordanMartinez Sep 25, 2020
5ab4e52
Rework the Monoid explanation when referring to its newtypes
JordanMartinez Sep 26, 2020
07bef30
Use "C-family" rather than "C-deriving" rendering
JordanMartinez Sep 26, 2020
8d79a6b
Refer to `void` as a keyword and fix comma mistake
JordanMartinez Sep 26, 2020
24f4ca7
Use 'void of C-family languages' rendering
JordanMartinez Sep 26, 2020
d939da5
Remove unneeded `do` in Array's Bind explanation
JordanMartinez Sep 26, 2020
b424064
Provide a simple graph reduction of examples in Array's Bind explanation
JordanMartinez Sep 26, 2020
a608415
Fix spacing between closing ]
JordanMartinez Sep 26, 2020
105a53e
Explain concept precisely and then use nested for loop intuition
JordanMartinez Sep 26, 2020
85039e8
Change Array's element type to String to match example
JordanMartinez Sep 26, 2020
6e14a53
Merge branch 'master' into addDocs
hdgarrood Sep 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/Control/Apply.purs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ import Control.Category (identity)
-- | the function application operator `($)` to arguments wrapped with the
-- | type constructor `f`.
-- |
-- | Put differently...
-- | ```
-- | foo =
-- | functionTakingNArguments <$> computationProducingArg1
-- | <*> computationProducingArg2
-- | <*> ...
-- | <*> computationProducingArgN
-- | ```
-- |
-- | Instances must satisfy the following law in addition to the `Functor`
-- | laws:
-- |
Expand Down
20 changes: 20 additions & 0 deletions src/Control/Bind.purs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,26 @@ infixr 1 bindFlipped as =<<
instance bindFn :: Bind ((->) r) where
bind m f x = f (m x) x

-- | The `bind`/`>>=` function for `Array` works by applying a function to
-- | each element in the array, and flattening the results into a single,
-- | new array.
-- |
-- | Array's `bind`/`>>=` works like a nested for loop. Each `bind` adds
-- | another level of nesting in the loop. For example:
-- | ```
-- | foo :: Array String
-- | foo =
-- | ["a", "b"] >>= \eachElementInArray1 ->
-- | ["c", "d"] >>= \eachElementInArray2
-- | pure (eachElementInArray1 <> eachElementInArray2)
-- |
-- | -- In other words...
-- | foo
-- | -- ... is the same as...
-- | [ ("a" <> "c"), ("a" <> "d"), ("b" <> "c"), ("b" <> "d") ]
-- | -- which simplifies to...
-- | [ "ac", "ad", "bc", "bd" ]
-- | ```
instance bindArray :: Bind Array where
bind = arrayBind

Expand Down
1 change: 1 addition & 0 deletions src/Control/Monad.purs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import Data.Unit (Unit)
class (Applicative m, Bind m) <= Monad m

instance monadFn :: Monad ((->) r)

instance monadArray :: Monad Array

-- | `liftM1` provides a default implementation of `(<$>)` for any
Expand Down
13 changes: 13 additions & 0 deletions src/Data/Monoid.purs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ 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
Copy link
Contributor

Choose a reason for hiding this comment

The 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 plus and zero, and the Multiplicative newtype has a Monoid instance which is based on Semiring's mul and one. There are a number of similar newtypes in the submodules of Data.Monoid in this package.

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).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also prefer not to call it a "workaround"

Agreed.

Does my rendering work? Or are there other changes you would prefer?

Copy link
Contributor

Choose a reason for hiding this comment

The 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`. Let's use `Int` as an example
-- | 1. `<>` could be `+` and `mempty` could be `0`
-- | 2. `<>` could be `*` and `mempty` could be `1`.
-- |
-- | To clarify these ambiguous situations, one should use the newtypes
-- | defined in `Data.Monoid.<NewtypeName>` modules.
-- |
-- | In the above ambiguous situation, we could use `Additive`
-- | for the first situation or `Multiplicative` for the second one.
class Semigroup m <= Monoid m where
mempty :: m

Expand Down
11 changes: 10 additions & 1 deletion src/Data/Semigroup.purs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The 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`.
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

@JordanMartinez JordanMartinez Sep 26, 2020

Choose a reason for hiding this comment

The 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 Monoid. It's better for a reader to read this, then read the Data.Semigroup.First documentation, and then think, "I get what Semigroup and First are, and First is not something I need. However, I know where to go if I do need it later" rather than "I get what a Semigroup is" and only later come across First and have to infer its relation.

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The 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

Expand Down
14 changes: 13 additions & 1 deletion src/Data/Void.purs
Original file line number Diff line number Diff line change
Expand Up @@ -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 keyword `void` that commonly appears in
-- | C-family 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 `void` of C-family languages above.
newtype Void = Void Void

instance showVoid :: Show Void where
Expand Down