content: typeclasses
This commit is contained in:
parent
0ba475fd83
commit
a00d8f26a6
|
@ -20,7 +20,7 @@ export default defineConfig({
|
||||||
remarkDirective,
|
remarkDirective,
|
||||||
// NOTE: pinned ^5.0.0
|
// NOTE: pinned ^5.0.0
|
||||||
remarkMath,
|
remarkMath,
|
||||||
[remarkEmoji, {accessible: true}],
|
[remarkEmoji as any, {accessible: true}],
|
||||||
[remarkRuby, {sep: ';'}],
|
[remarkRuby, {sep: ';'}],
|
||||||
remarkBib,
|
remarkBib,
|
||||||
],
|
],
|
||||||
|
|
10
package.json
10
package.json
|
@ -15,7 +15,7 @@
|
||||||
"@astrojs/solid-js": "^3.0.2",
|
"@astrojs/solid-js": "^3.0.2",
|
||||||
"@citation-js/plugin-bibtex": "^0.7.2",
|
"@citation-js/plugin-bibtex": "^0.7.2",
|
||||||
"@js-temporal/polyfill": "^0.4.4",
|
"@js-temporal/polyfill": "^0.4.4",
|
||||||
"astro": "^3.4.3",
|
"astro": "^3.4.4",
|
||||||
"astro-pagefind": "^1.3.0",
|
"astro-pagefind": "^1.3.0",
|
||||||
"chart.js": "^4.4.0",
|
"chart.js": "^4.4.0",
|
||||||
"citation-js": "^0.7.4",
|
"citation-js": "^0.7.4",
|
||||||
|
@ -39,10 +39,10 @@
|
||||||
"unist-util-visit": "^5.0.0"
|
"unist-util-visit": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/leaflet": "^1.9.7",
|
"@types/leaflet": "^1.9.8",
|
||||||
"@types/leaflet.markercluster": "^1.5.3",
|
"@types/leaflet.markercluster": "^1.5.4",
|
||||||
"@types/reveal.js": "^4.4.5",
|
"@types/reveal.js": "^4.4.6",
|
||||||
"@types/unist": "^3.0.1",
|
"@types/unist": "^3.0.2",
|
||||||
"pagefind": "^1.0.3",
|
"pagefind": "^1.0.3",
|
||||||
"sass": "^1.69.5",
|
"sass": "^1.69.5",
|
||||||
"sharp": "^0.32.6"
|
"sharp": "^0.32.6"
|
||||||
|
|
472
pnpm-lock.yaml
472
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,7 @@ I've found them pretty confusing, but in reality they are an incredibly elegant
|
||||||
|
|
||||||
## Why?
|
## Why?
|
||||||
|
|
||||||
In Haskell, we can write monomorphic functions which accepts concrete types.
|
In Haskell, we can write monomorphic functions which accept concrete types.
|
||||||
As an example, the function `add` shown below adds together two values of type `Int`.
|
As an example, the function `add` shown below adds together two values of type `Int`.
|
||||||
|
|
||||||
```haskell
|
```haskell
|
||||||
|
@ -138,10 +138,100 @@ When `Num` is applied to `Int`, it becomes a constraint on the `Int` type, indic
|
||||||
```haskell
|
```haskell
|
||||||
Num Int :: Constraint
|
Num Int :: Constraint
|
||||||
```
|
```
|
||||||
|
Another example of a kind in Haskell is the kind of unary type constructors `* -> *`.
|
||||||
|
These unary type constructors are similar to generic types in other languages because they accept a type parameter and produce a new type.
|
||||||
|
The signature `* -> *` signifies that the type constructor transforms one concrete type into another concrete type.
|
||||||
|
|
||||||
|
An example of a trivial type constructor `Item` is shown below.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
data Item a = MkItem a
|
||||||
|
|
||||||
|
Item :: * -> *
|
||||||
|
Item Int :: *
|
||||||
|
Item String :: *
|
||||||
|
```
|
||||||
|
|
||||||
|
In this definition, `Item` is a unary type constructor because it takes a type parameter `a` and produces a new type `Item a`, where `a` can be any concrete type.
|
||||||
|
|
||||||
|
A commonly used example of a unary type constructor in Haskell is the `Maybe` type.
|
||||||
|
`Maybe` is used for representing optional values and handling potentially missing or undefined data in a type-safe manner.
|
||||||
|
Its definition is as follows:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
data Maybe a = Nothing | Just a
|
||||||
|
|
||||||
|
Maybe :: * -> *
|
||||||
|
```
|
||||||
|
|
||||||
|
Haskell type constructors can be parameterized with more than one type variable, as seen in the case of binary type constructors.
|
||||||
|
An example of a binary type constructor is the `Either` data type:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
data Either a b = Left a | Right b
|
||||||
|
|
||||||
|
Either :: * -> * -> *
|
||||||
|
Either String :: * -> *
|
||||||
|
Either String Int :: *
|
||||||
|
```
|
||||||
|
|
||||||
|
In this definition, `Either` is a binary type constructor because it requires two type parameters, `a` and `b`, to create a new type, `Either a b`.
|
||||||
|
The `Either` type is often used for scenarios where a value can have one of two possible types, such as representing success or failure or providing an alternative to error handling.
|
||||||
|
Conventionally, the `Left` value indicates error conditions, while the `Right` value signifies valid or correct values.
|
||||||
|
|
||||||
|
|
||||||
### Higher Kinded Types
|
### Higher Kinded Types
|
||||||
|
|
||||||
### The venerable monad
|
In Haskell, understanding the concept of "Higher Kinded Types" is crucial for grasping how certain more abstract type classes work.
|
||||||
|
HKTs involve type classes that are parameterized by type constructors, rather than just simple types.
|
||||||
|
|
||||||
|
The `Functor` type class is an example of a HKT class.
|
||||||
|
It defines two fundamental operations, `fmap` and `<$`, which operate on a type constructor `f`.
|
||||||
|
|
||||||
|
The Functor type class is defined as follows:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
class Functor f where
|
||||||
|
fmap :: (a -> b) -> f a -> f b
|
||||||
|
(<$) :: a -> f b -> f a
|
||||||
|
|
||||||
|
Functor :: (* -> *) -> Constraint
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Functor` type class is not constrained to specific types but is rather parameterized by type constructors.
|
||||||
|
Its kind signature is `(* -> *) -> Constraint`, indicating that it works with type constructors.
|
||||||
|
This allows it to be applied to types like `Maybe`, `List`, or other container types that accept a type argument.
|
||||||
|
|
||||||
|
Similarly to `Functor`, the `Monad` type class is another example of a HKT type class.
|
||||||
|
It defines functions for monadic operations, such as `>>=`, `>>`, and `return`.
|
||||||
|
|
||||||
|
The definition of the `Monad` type class is as follows:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
class Monad m where
|
||||||
|
(>>=) :: m a -> ( a -> m b) -> m b
|
||||||
|
(>>) :: m a -> m b -> m b
|
||||||
|
return :: a -> m a
|
||||||
|
|
||||||
|
Monad :: (* -> *) -> Constraint
|
||||||
|
```
|
||||||
|
|
||||||
|
Like the `Functor` type class, the `Monad` type class is not tied to specific types but is parameterized by type constructors.
|
||||||
|
Its kind signature is also `(* -> *) -> Constraint`.
|
||||||
|
|
||||||
|
It is worth noting that type classes with a kind of `(* -> *) -> Constraint` can be applied to kinds like `* -> * -> *`.
|
||||||
|
An example of this is the `Functor` instance of `Either`:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
instance Functor (Either a) where
|
||||||
|
fmap _ (Left x) = Left x
|
||||||
|
fmap f (Right x) = Right (f x)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
In the instance declaration above, we specify that, for any type `a`, `Either a` is an instance of the `Functor` type class.
|
||||||
|
This allows you to use the `fmap` function with `Either a`, providing a way to map over the second type argument of the `Either` type while keeping the first type argument fixed.
|
||||||
|
|
||||||
|
|
||||||
## Other languages
|
## Other languages
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue