Skip to content

Commit 9d0b57f

Browse files
committed
2 parents 9946bff + abd9d63 commit 9d0b57f

File tree

5 files changed

+57
-6
lines changed

5 files changed

+57
-6
lines changed

_chapters/haskell3.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,7 @@ This will allow us to make more functions point-free
869869

870870
```haskell
871871
square :: Num a => a => a
872-
square = a * a
872+
square a = a * a
873873
```
874874

875875
```haskell
@@ -888,7 +888,7 @@ class Applicative f => Alternative (f :: * -> *) where
888888
(<|>) :: f a -> f a -> f a
889889
```
890890

891-
`empty`: This function represents a computation with *no result or a failure*. It serves as the identity element. For different data types that are instances of Alternative, `empty` represents an empty container or a *failed computation*, depending on the context.
891+
`empty`: This function represents a computation with either *no result, or a failure*. It serves as the identity element. For different data types that are instances of Alternative, `empty` represents an empty container or a *failed computation*, depending on the context.
892892

893893
`(<|>)`: The `<|>` operator combines two computations, and its used to express alternatives. It takes two computations of the same type and returns a computation that will produce a result from the first computation if it succeeds, or if it fails, it will produce a result from the second computation. This operator allows you to handle branching logic and alternative paths in your code.
894894

_chapters/haskell4.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Note that since the `(+)` operator is associative—a+(b+c) = (a+b)+c—`foldr`
104104

105105
## Monoid
106106

107-
In the example fold above, we provide the `(+)` function to tell `foldl` how to aggregate elements of the list. There is also a typeclass for things that are “automatically aggregatable” or “concatenatable” called `Monoid` which declares a general function for `mappend` combining two `Monoid`s into one, a `mempty` value such that any Monoid `mappend`'ed with `mempty` is itself, and a concatenation function for lists of `Monoid` called `mconcat`.
107+
In the example fold above, we provide the `(+)` function to tell `foldl` how to aggregate elements of the list. There is also a typeclass for things that are “automatically aggregable” or “concatenatable” called `Monoid` which declares a general function for `mappend` combining two `Monoid`s into one, a `mempty` value such that any Monoid `mappend`'ed with `mempty` is itself, and a concatenation function for lists of `Monoid` called `mconcat`.
108108

109109
```haskell
110110
Prelude> :i Monoid
@@ -133,7 +133,7 @@ Prelude Data.Monoid> getSum $ mconcat $ Sum <$> [5,8,3,1,7,6,2]
133133

134134
> 32
135135
136-
We make a data type aggregatable by instancing `Monoid` and providing definitions for the functions `mappend` and `mempty`. For `Sum` these will be `(+)` and `0` respectively.
136+
We make a data type aggregable by instancing `Monoid` and providing definitions for the functions `mappend` and `mempty`. For `Sum` these will be `(+)` and `0` respectively.
137137
Lists are also themselves Monoidal, with `mappend` defined as an alias for list concatenation `(++)`, and mempty as `[]`. Thus, we can:
138138

139139
```haskell

_chapters/javascript1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1119,7 +1119,7 @@ class Person:
11191119
self.occupation = occupation
11201120

11211121
@property
1122-
def greeting():
1122+
def greeting(self):
11231123
return f"Hi, my name's {self.name} and I {self.occupation}!"
11241124

11251125
def say_hello(self):

_chapters/monad.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ they all take a common parameter, e.g. a line break character.
399399
```haskell
400400
greet linebreak = "Dear Gentleperson,"++linebreak
401401
body sofar linebreak = sofar ++ linebreak ++ "It has come to my attention that… " ++ linebreak
402-
signoff sofar linebreak = sofar ++ linebreak ++ "Your’s truly," ++ linebreak ++ "Tim" ++ linebreak
402+
signoff sofar linebreak = sofar ++ linebreak ++ "Yours truly," ++ linebreak ++ "Tim" ++ linebreak
403403
putStrLn $ (greet >>= body >>= signoff) "\r\n"
404404
```
405405

_chapters/parsercombinators.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,57 @@ The parser combinator discussed here is based on one developed by Tony Morris an
2525

2626
You can play with the example and the various parser bits and pieces in [this online playground](https://replit.com/@tgdwyer/Parser-Examples).
2727

28+
## Why do we need Monads ?
29+
30+
Consider the task of parsing the following string:
31+
32+
```haskell
33+
5abcdefg
34+
```
35+
36+
In this example, the number `5` specifies how many characters should be parsed from the rest of the string.
37+
The goal is to obtain the result:
38+
39+
```haskell
40+
Just ("fg", "abcde")
41+
```
42+
43+
The parser should first read the number 5, then use that value to determine how many characters to extract `"abcde"`, leaving the remainder `"fg"` unparsed. The key question here is: Can we achieve this using only `Functor` and `Applicative`?
44+
45+
The answer is no. Both of these abstractions allow us to combine independent computations, but they do not allow one computation to depend on the result of another. Using a Monad, we can **sequence** computations where the output of one step influences the next step’s behavior, which is precisely what this parsing task requires.
46+
47+
So, if we have these two parsers:
48+
49+
```haskell
50+
parseInt :: Parser Int
51+
parseInt = int
52+
53+
parseNCharacters :: Int -> Parser String
54+
parseNCharacters 0 = pure ""
55+
parseNCharacters n = liftA2 (:) char (parseNCharacters (n-1))
56+
```
57+
58+
We want a way to combine these two parsers — first run `parseInt`, then pass its result to `parseNCharacters`. Let’s imagine a new operator that could do this:
59+
60+
```haskell
61+
newOperator :: Parser Int -> (Int -> Parser String) -> Parser String
62+
```
63+
64+
Using this operator, we could write:
65+
66+
```haskell
67+
parse (newOperator parseInt parseNCharacters) "5abcdefg"
68+
= Just ("fg", "abcde")
69+
```
70+
71+
When we generalize this `newOperator` idea, to any container, we get:
72+
73+
```haskell
74+
(>>=) :: f a -> (a -> f b) -> f b
75+
```
76+
77+
This operator is called `bind`, and it is the core of the `Monad` type class. This is a very powerful concept, it allows you to chain dependent computations where the output of one step determines the next step. This is exactly why `Monads` go beyond `Functors` and `Applicatives`: they enable sequencing with dependency.
78+
2879
## Context-free Grammars and BNF
2980

3081
Fundamental to the analysis of human natural language but also to the design of programming languages is the idea of a *grammar*, or a set of rules for how elements of the language may be composed. A context-free grammar (CFG) is one in which the set of rules for what is produced for a given input (*production rules*) completely covers the set of possible input symbols (i.e. there is no additional context required to parse the input). Backus-Naur Form (or BNF) is a notation that has become standard for writing CFGs since the 1960s. We will use BNF notation from now on. There are two types of symbols in a CFG: *terminal* and *non-terminal*. In BNF non-terminal symbols are `<nameInsideAngleBrackets>` and can be converted into a mixture of terminals and/or nonterminals by production rules:

0 commit comments

Comments
 (0)