a -> a -> a) While we may expect them to behave in some common ways, the exact meaning of that depends on the specific type. Why not write functions that could work on any of these types with respect to this combining behaviour?
Semigroup. Don't let the math-y name scare you! It's actually very straightforward for a "combinable" thing.
x, then you can also do
y!" It lets you extend abstract interfaces with more functions. This usually makes for a smaller number of types that have the new interface, because they need the old type class, plus an instance for the new one, which is not always even possible!
<>is a no op. We'll call this
mempty, because of how it works on lists ( ++ xs = xs) and because the name
idwas already taken.
<>automatically available. Let's look at a few of these:
Functortree, which includes the infamour
Monadclass. These also have special rules that you need to obey when writing instances for, but you'll mostly be using someone else's so don't worry about them too much for now.
fmap's operator variants
$(application) but working on something that's been put into a container (practically any sum or product type), hence the visual pun of
<gt;. Same goes for
Applicatives add a lot of power to
Functorsby defining two functions:
pure(also known as the somewhat confusingly named
return) takes a plain value and wraps it in a container.
<*>does function application when both functions and arguments are wrapped
>>=is special compared to
<*>. It doesn't run out of arguments, and can be chained forever.
>>=and nesting to keep it straight. Haskell has "do notation" to clean this up, make it feel like an linear set of instructions, and also pun on a lot of imperative programming.
return, which is the same function but renamed for extra imperative punning.
letthat lets you skip the
<-for simple values.
classdeclaration, or in the same module as a datatype definition. But what happens when you need to add an instance from a library to a datatype that's also from a library?
Fission.Internal.Orphanage. Importing this module doesn't have any actual exports, but you do need to signal to the compiler that it's a dependency for the module that you're writing. Importing it normally will lead to the linter complaining about an unused import. You can get around this warning by explicitely showiung that are no imports: