diff --git a/_chapters/haskell2.md b/_chapters/haskell2.md index 2743c10d..8cd976c1 100644 --- a/_chapters/haskell2.md +++ b/_chapters/haskell2.md @@ -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. ## Pattern Matching diff --git a/_chapters/monad.md b/_chapters/monad.md index 96e1509c..951258d2 100644 --- a/_chapters/monad.md +++ b/_chapters/monad.md @@ -137,8 +137,8 @@ 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: @@ -146,10 +146,13 @@ So GHCi is telling us that the next argument has to be a function that takes a ` ```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) @@ -157,6 +160,17 @@ Just (-1.0,-2.0) 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 @@ -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: diff --git a/_sass/minima/custom-styles.scss b/_sass/minima/custom-styles.scss index 162b82c4..606a3ba7 100644 --- a/_sass/minima/custom-styles.scss +++ b/_sass/minima/custom-styles.scss @@ -1,3 +1,7 @@ +#play-theme-song { + color: var(--minima-site-title-color); +} + .cheatsheet, .glossary { background-color: #f3f0f0; padding: 8px 12px;