Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion _chapters/haskell2.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ student = UserId 1337

The `newtype` keyword is used to define a type that has *exactly* one constructor with *exactly* one field. It is primarily used for creating a distinct type from an existing type with *zero runtime* overhead. This can be useful for adding type safety to your code by creating new types that are distinct from their underlying types or giving types a greater semantic meaning, e.g., a UserId compared to an Int.

The data keyword is used to define an algebraic data type (ADT). This allows for the creation of complex data structures that can have multiple constructors. Each constructor can take zero or more arguments, and these arguments can be of any type.
The `data` keyword is used to define an algebraic data type (ADT). This allows for the creation of complex data structures that can have multiple constructors. Each constructor can take zero or more arguments, and these arguments can be of any type.
</div>

## Pattern Matching
Expand Down
30 changes: 23 additions & 7 deletions _chapters/monad.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,26 +137,40 @@ The first argument it expects is a value in a context `m a`. What if that we ap

```haskell
> x = 1::Float
> :t (Just x>>=)
(Just x>>=) :: (Float -> Maybe b) -> Maybe b
> :t (Just x >>=)
(Just x >>=) :: (Float -> Maybe b) -> Maybe b
```

So GHCi is telling us that the next argument has to be a function that takes a `Float` as input, and gives back anything in a `Maybe`. Our `safeSqrt` definitely fits this description, as does `safeDiv` partially applied to a `Float`. So, here’s a `safeSolve` which uses `(>>=)` to remove the need for `case`s:

```haskell
safeSolve :: Float -> Float -> Float -> Maybe (Float, Float)
safeSolve a b c =
safeSqrt (b*b - 4 * a * c) >>= \s ->
safeDiv (-b + s) (2*a) >>= \x1 ->
safeDiv (-b - s) (2*a) >>= \x2 ->
pure (x1,x2)
safeSqrt (b*b - 4 * a * c) >>= \s -> (
safeDiv (-b + s) (2*a) >>= \x1 -> (
safeDiv (-b - s) (2*a) >>= \x2 -> (
pure (x1,x2)
)
)
)

> safeSolve 1 3 2
Just (-1.0,-2.0)
> safeSolve 1 1 2
Nothing
```

We actually don't need all the brackets, so we could have written `safeSolve` as the following:

```haskell
safeSolve :: Float -> Float -> Float -> Maybe (Float, Float)
safeSolve a b c =
safeSqrt (b*b - 4 * a * c) >>= \s ->
safeDiv (-b + s) (2*a) >>= \x1 ->
safeDiv (-b - s) (2*a) >>= \x2 ->
pure (x1,x2)
```

Note that Haskell has a special notation for such multi-line use of bind, called “`do` notation”. The above code in a `do` block looks like:

```haskell
Expand Down Expand Up @@ -337,13 +351,15 @@ do
which is itself syntactic sugar for:

```haskell
['a'..'d'] >>= \i -> ([1..4] >>= \j -> pure (i,j))
-- without the brackets:
['a'..'d'] >>= \i -> [1..4] >>= \j -> pure (i,j)
```

List comprehensions can also include conditional expressions which must evaluate to true for terms to be included in the list result. For example, we can limit the above comprehension to only pairs with even `j`:

```haskell
[(i,j) | i<-['a'..'d'], j<-[1..4], j `mod` 2 == 0]
[(i, j) | i <- ['a'..'d'], j <- [1..4], j `mod` 2 == 0]
```

This comprehension syntax desugars to a `do`-block using the `guard` function from `Control.Monad` like so:
Expand Down
4 changes: 4 additions & 0 deletions _sass/minima/custom-styles.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#play-theme-song {
color: var(--minima-site-title-color);
}

.cheatsheet, .glossary {
background-color: #f3f0f0;
padding: 8px 12px;
Expand Down