summaryrefslogtreecommitdiff
path: root/lec07/notes.md
diff options
context:
space:
mode:
authorEdoardo La Greca2025-09-08 21:24:40 +0200
committerEdoardo La Greca2025-09-08 21:24:40 +0200
commit476ae2fe83ea46e3845b0c32afe7df57c8fb109b (patch)
tree5bde49eba9acb1837844606ef11746d3918fdd95 /lec07/notes.md
parentc524968f3e4247ca674fe112a0b8e7081ab65b19 (diff)
add rest of notes for lecture 7
Diffstat (limited to 'lec07/notes.md')
-rw-r--r--lec07/notes.md61
1 files changed, 61 insertions, 0 deletions
diff --git a/lec07/notes.md b/lec07/notes.md
index b59d6e9..18f9828 100644
--- a/lec07/notes.md
+++ b/lec07/notes.md
@@ -56,3 +56,64 @@ The reason why we just implemented a fold for trees is to state a fact: folds ar
In general, a fold function for any given type `T` takes one argument for each of `T`'s constructors. Each of these arguments is a function that indicates how to translate the respective constructor and combine its data into an expression suitable for the final result. Many functions are expressible as simple folds, that's why it's important to grasp its concept.
+## Monoids
+
+Monoids are one of the standard type classes. We can find its definition in the `Data.Monoid` module. Monoids are defined as follows.
+
+ class Monoid m where
+ mempty :: m
+ mappend :: m -> m -> m
+ mconcat :: [m] -> m
+ mconcat = foldr mappend mempty
+
+ (<>) :: Monoid m => m -> m -> m
+ (<>) = mappend
+
+As we can see, instances of `Monoid` define an element called `mempty` and a function called `mappend`, the latter equivalently named `(<>)`. `mempty` and `mappend` have two important properties: `mappend` satisfies associativity, and `mempty` is the identity value for `mappend`.
+
+Associativity means that, in an expression or sub-expression made of `mappend` operations only, regardless of how we arrange their arguments and associate (i.e. parenthesize) the operations, the final result is going to be the same.
+
+In addition to that, identity means that `mempty` is a special value: if given as one of the two arguments of an `mappend` function, the function returns its other argument. Obviously, if the both arguments are the identity, the result is going to be the identity again.
+
+`mconcat` is just a shorthand for combining a list of values. Although its default implementation uses `foldr`, there might be more efficient ways of implementing it depending on the particular instance of `Monoid`.
+
+An example monoid for lists, as the function names suggest, would be:
+
+ instance Monoid [a] where
+ mempty = []
+ mappend = (++)
+
+And this would be all about monoids, but what if we had two possible monoids for the same type? For example, both addition and multiplication are suitable monoids for integers, but we can't create more than one instance of a type class for the same type.
+
+We can solve this issue by creating a new type for each instance we want to create:
+
+ newtype Sum a = Sum a
+ deriving (Eq, Ord, Num, Show)
+
+ getSum :: Sum a -> a
+ getSum (Sum a) = a
+
+ instance Num a => Monoid (Sum a) where
+ mempty = Sum 0
+ mappend = (+)
+
+ newtype Product a = Product a
+ deriving (Eq, Ord, Num, Show)
+
+ getProduct :: Product a -> a
+ getProduct (Product a) = a
+
+ instance Num a => Monoid (Product a) where
+ mempty = Product 1
+ mappend = (*)
+
+### Answers to the two final challenges
+
+It's possible to make an instance of `Monoid` for `Bool`, but there are as many instances as boolean operators: one for AND, one for OR, one for XOR, etc. The reason is that, like integers, boolean values have different associative functions, each with its own identity value.
+
+Instances of `Monoid` for function types can be defined like this:
+
+ instance Monoid (a -> a) where
+ mempty = id
+ mappend = .
+