diff --git a/fp/.obsidian/appearance.json b/fp/.obsidian/appearance.json
index 88334d1..5cb9285 100644
--- a/fp/.obsidian/appearance.json
+++ b/fp/.obsidian/appearance.json
@@ -2,5 +2,6 @@
"theme": "obsidian",
"accentColor": "#745eff",
"interfaceFontFamily": "",
- "baseFontSize": 20
+ "baseFontSize": 22,
+ "nativeMenus": false
}
\ No newline at end of file
diff --git a/fp/.obsidian/graph.json b/fp/.obsidian/graph.json
index 2ade83f..9e9cd95 100644
--- a/fp/.obsidian/graph.json
+++ b/fp/.obsidian/graph.json
@@ -17,6 +17,6 @@
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
- "scale": 0.6174207201407237,
+ "scale": 0.36924895020525084,
"close": true
}
\ No newline at end of file
diff --git a/fp/.obsidian/workspace.json b/fp/.obsidian/workspace.json
index 288c4c8..bbae538 100644
--- a/fp/.obsidian/workspace.json
+++ b/fp/.obsidian/workspace.json
@@ -4,11 +4,11 @@
"type": "split",
"children": [
{
- "id": "1ae4bfe7bb551ca1",
+ "id": "eecc282740820263",
"type": "tabs",
"children": [
{
- "id": "d3a2cb4690ca618a",
+ "id": "6465d16034124b8f",
"type": "leaf",
"state": {
"type": "graph",
@@ -65,8 +65,7 @@
}
],
"direction": "horizontal",
- "width": 300,
- "collapsed": true
+ "width": 300
},
"right": {
"id": "75cf567121b661bb",
@@ -141,12 +140,32 @@
"publish:Publish changes...": false
}
},
- "active": "d3a2cb4690ca618a",
+ "active": "6465d16034124b8f",
"lastOpenFiles": [
+ "Classes/Alternative/Alt.md",
+ "Classes/Alternative/Plus.md",
+ "Monads/Transformers/MaybeT.md",
+ "Monads/Transformers/ExceptT.md",
+ "Monads/Transformers/ReaderT.md",
+ "Monads/Transformers/WriterT.md",
+ "Monads/Transformers/StateT.md",
+ "Monads/Transformers",
+ "Classes/Alternative/Alternative.md",
+ "Classes/Functor/Applicative.md",
+ "Classes/Functor/Apply.md",
+ "Classes/Functor/Functor.md",
+ "Classes/Collapsing",
+ "Classes/Bind",
+ "Classes/Functor",
+ "Classes/Alternative",
+ "Language/Infix Operators/Common Operators/Data.md",
+ "Classes/Traversable.md",
+ "Data/Collections/NonEmptyArray.md",
+ "Data/Collections/NonEmptyList.md",
+ "Data/String.md",
"Data/Collections.md",
"Data/Collections/HashMap.md",
"Data/Product",
- "Data/Untitled.md",
"Data/Sum",
"Data/Collections/HashSet.md",
"Data/Collections/Set.md",
@@ -158,27 +177,7 @@
"Language/Row Types/Record.md",
"Data/Product/Tuple.md",
"Language/Row Types",
- "Data/Sum/Either.md",
- "Language/Functions.md",
- "Language/Functions/Defining/Guard Clause.md",
- "Language/Typeclasses.md",
- "Language/Type Signature.md",
- "Class/Monoid.md",
- "Class/Semigroup.md",
- "Class/Math/EuclideanRing.md",
- "Class/Math/Semiring.md",
- "Class/Math/DivisionRing.md",
- "Class/Math/Ring.md",
- "Class/Semiring.md",
- "Class/Math",
- "Class/Foldable.md",
- "Terminology/Purity.md",
- "Language/Expressions/do notation.md",
- "Monads/Classes/Stack-safe recursion",
- "Monads/Classes/Early Return",
- "Monads/Classes/State",
- "Monads/Classes/F",
- "Monads/Classes/Error Handling",
+ "Classes/Math",
"Untitled 1.canvas",
"Untitled.canvas"
]
diff --git a/fp/Class/Apply.md b/fp/Class/Apply.md
deleted file mode 100644
index fb1c22d..0000000
--- a/fp/Class/Apply.md
+++ /dev/null
@@ -1,12 +0,0 @@
-Generalizes [[Functor]] to functions with 2+ arguments
-
-```haskell
-apply ::
- forall f a b
- . Apply f
- => f (a -> b)
- -> f a
- -> f b
-
-infixl apply as <*>
-```
diff --git a/fp/Classes/Alternative/Alt.md b/fp/Classes/Alternative/Alt.md
new file mode 100644
index 0000000..4e7a5f9
--- /dev/null
+++ b/fp/Classes/Alternative/Alt.md
@@ -0,0 +1,52 @@
+Alt is used most often as boolean OR on fallible [[Functor|functors]], but is technically whatever associative operation makes sense for the [[Data Structures|data]] type.
+
+```haskell
+class Functor f <= Alt f where
+ alt :: forall a. f a -> f a -> f a
+```
+
+### Examples
+In [[Maybe]], Alt allows chainable defaults:
+```haskell
+Just 1 <|> Just 2
+-- Just 1
+
+Nothing <|> Just 1
+-- Just 1
+
+Nothing <|> Nothing
+-- Nothing
+
+Nothing <|> Nothing <|> Just 1
+-- Just 1
+```
+
+In [[Either]], Alt works as a try/catch:
+```haskell
+Left "error!" <|> Right "it's ok i recovered"
+-- Right "it's ok i recovered"
+
+Right "i succeeded!" <|> Right "backup"
+-- Right "i succeeded!"
+
+Right unit <|> Left "uh oh!"
+-- Right unit
+
+Left "a" <|> Left "b"
+-- Left "b"
+```
+
+> [!attention]
+> Note that Alt in Either takes the last `Left` when all are `Left`!
+
+In [[Array]], Alt is append:
+```haskell
+[] <|> [] -- []
+
+["a"] <|> [] -- ["a"]
+
+[] <|> ["a"] -- ["a"]
+
+["a"] <|> ["b"] -- ["a", "b"]
+["a"] <|> ["b", "c"] -- ["a", "b", "c"]
+```
\ No newline at end of file
diff --git a/fp/Classes/Alternative/Alternative.md b/fp/Classes/Alternative/Alternative.md
new file mode 100644
index 0000000..96cc1d7
--- /dev/null
+++ b/fp/Classes/Alternative/Alternative.md
@@ -0,0 +1 @@
+Doesn't have any class members, just requires that `f` in `Alternative f` must also be [[Plus]] and [[Alt]].
\ No newline at end of file
diff --git a/fp/Classes/Alternative/Plus.md b/fp/Classes/Alternative/Plus.md
new file mode 100644
index 0000000..c6dd387
--- /dev/null
+++ b/fp/Classes/Alternative/Plus.md
@@ -0,0 +1,39 @@
+Extends [[Alt]] with an empty value:
+
+```haskell
+class Alt f <= Plus f where
+ empty :: forall a. f a
+```
+
+> [!info]
+> Conceptually, this lives next to [[Applicative|pure]] in my mind; in [[Maybe]] for example `pure` and `empty` are aliases for `Just` and `Nothing`.
+
+In [[Array]], `empty` is empty array `[]`. In [[Maybe]], `empty` is `Nothing`.
+
+The most common place you'll see `empty` is when using [[MaybeT]] as an early return:
+
+```haskell
+logDebug :: String -> Effect Unit
+logDebug msg = void $ runMaybeT do
+ env <- MaybeT $ Process.lookupEnv "NODE_ENV"
+ when (env /= "DEVELOPMENT") empty
+ lift $ Console.log msg
+```
+
+this is equivalent to:
+
+```haskell
+logDebug :: String -> Effect Unit
+logDebug msg = do
+ menv <- Process.lookupEnv "NODE_ENV"
+ case menv of
+ Just env ->
+ if env == "DEVELOPMENT" then
+ Console.log msg
+ else
+ pure unit
+ Nothing -> pure unit
+```
+
+> [!info]
+> Note that [guard](https://pursuit.purescript.org/packages/purescript-control/docs/Control.Alternative#v:guard) is a shorthand available for `when (..) empty`
\ No newline at end of file
diff --git a/fp/Class/Bind.md b/fp/Classes/Bind/Bind.md
similarity index 100%
rename from fp/Class/Bind.md
rename to fp/Classes/Bind/Bind.md
diff --git a/fp/Class/Monad.md b/fp/Classes/Bind/Monad.md
similarity index 100%
rename from fp/Class/Monad.md
rename to fp/Classes/Bind/Monad.md
diff --git a/fp/Class/Foldable.md b/fp/Classes/Foldable.md
similarity index 100%
rename from fp/Class/Foldable.md
rename to fp/Classes/Foldable.md
diff --git a/fp/Classes/Functor/Applicative.md b/fp/Classes/Functor/Applicative.md
new file mode 100644
index 0000000..98c4b9c
--- /dev/null
+++ b/fp/Classes/Functor/Applicative.md
@@ -0,0 +1,18 @@
+Adds the `pure` [[Functions|function]] to [[Apply]], allowing arbitrary values to be wrapped in a [[Functor]].
+
+```haskell
+class Apply f <= Applicative f where
+ pure :: forall a. a -> f a
+```
+
+### Examples
+`pure a` in various types:
+
+type|equivalent to
+---|---
+[[Array]]|`[a]`
+[[List]]|`Cons a`
+[[Maybe]]|`Just a`
+[[Either]]|`Right a`
+[[Effect]]|`() => a`more or less
+[[Aff]]|`Promise.resolve(a)`more or less
\ No newline at end of file
diff --git a/fp/Classes/Functor/Apply.md b/fp/Classes/Functor/Apply.md
new file mode 100644
index 0000000..b902b2b
--- /dev/null
+++ b/fp/Classes/Functor/Apply.md
@@ -0,0 +1,79 @@
+Generalizes [[Functor#map|map]] to [[Functions|functions]] with 2+ arguments; lifting functions `a -> b -> c` to `f a -> f b -> f c`
+
+```haskell
+class Functor f <= Apply f where
+ apply :: forall a b. f (a -> b) -> f a -> f b
+
+infixl apply as <*>
+```
+
+> [!tip]
+> Apply often replaces the pattern of "building towards a final result"
+>
+> Consider a function that [[Tuple|tuple]]s together its arguments
+> ```haskell
+> mk3Tuple a b c = a /\ b /\ c
+> ```
+>
+> A common situation is wanting to build something like this 3-tuple from some components that are trapped in a context like [[Maybe]] or [[Either]], and we want to say "when all these things are ok, build it"; this is exactly what Apply lets us do:
+>
+> ```haskell
+> maybeMk3Tuple :: Maybe a -> Maybe b -> Maybe c -> Maybe (a /\ b /\ c)
+> maybeMk3Tuple ma mb mc = Just mk3Tuple <*> ma <*> mb <*> mc
+>
+> maybeMk3Tuple (Just 1) (Just 2) (Just 3)
+> -- Just (1 /\ 2 /\ 3)
+>
+> maybeMk3Tuple (Just "a") (Just 3) (Nothing)
+> -- Nothing
+>
+> maybeMk3Tuple Nothing Nothing Nothing
+> -- Nothing
+> ```
+
+> [!tip]
+> Obscure but occasionally usefully, Apply in collections lets us apply multiple functions to each element:
+> ```haskell
+> [(_ * 10), (_ * 20)] <*> [1, 2, 3]
+> -- [10, 20, 20, 40, 30, 60]
+>
+> [identity, const ", "] <*> ["a", "b", "c"]
+> -- ["a", ",", "b", ",", "c", ","]
+> ```
+
+### Examples
+
+lift `(a + b) / c` to [[Maybe]]
+```haskell
+f :: Number -> Number -> Number
+f a b c = (a + b) / c
+
+mf :: Maybe Number -> Maybe Number -> Maybe Number
+mf ma mb mc = pure f <*> ma <*> mb <*> mc
+```
+
+Build up a `Person` [[Record|record]] from Maybe fields; short-circuiting to `Nothing` if any fields are `Nothing`
+```haskell
+type PartialPerson =
+ { name :: Maybe String
+ , email :: Maybe String
+ , password :: Maybe String
+ }
+
+type Person =
+ { name :: String
+ , email :: String
+ , password :: String
+ }
+
+person :: PartialPerson -> Person
+person
+ { name: name'
+ , email: email'
+ , password: password'
+ } =
+ let
+ buildPerson name email password = {name, email, password}
+ in
+ Just buildPerson <*> name' <*> email' <*> password'
+```
\ No newline at end of file
diff --git a/fp/Class/Functor.md b/fp/Classes/Functor/Functor.md
similarity index 69%
rename from fp/Class/Functor.md
rename to fp/Classes/Functor/Functor.md
index e777f08..b165dce 100644
--- a/fp/Class/Functor.md
+++ b/fp/Classes/Functor/Functor.md
@@ -1,4 +1,3 @@
-## What
[[Typeclasses|Typeclass]] defining the [[Functions|function]] `map`, [[Infix Operators|operators]] `<$>`, and `<#>`.
```haskell
@@ -6,11 +5,21 @@ class Functor f where
map :: forall a b. (a -> b) -> f a -> f b
```
-## Why
-Modify the data contained in a [[Data Structures|data structure]]
+## map
+For a [[Data Structures|data structure]] containing some data `a`, change the data using some function `a -> b`.
-### Abstracts
-- For every element in [[Collections|collection]] ...
+> [!info]
+> Another way of thinking of map is that it **lifts** a function of `a -> b` to `f a -> f b`:
+> ```haskell
+> addTwo :: Int -> Int
+> addTwo = add 2
+>
+> maybeAddTwo :: Maybe Int -> Maybe Int
+> maybeAddTwo = map addTwo
+> ```
+
+Replaces the patterns:
+- Modify every element in [[Collections|collection]] ...
- When [[Maybe|nullable]] value is non-null ...
- When _(potentially async)_ [[Effect|IO]] resolves ...
diff --git a/fp/Class/Math/DivisionRing.md b/fp/Classes/Math/DivisionRing.md
similarity index 100%
rename from fp/Class/Math/DivisionRing.md
rename to fp/Classes/Math/DivisionRing.md
diff --git a/fp/Class/Math/EuclideanRing.md b/fp/Classes/Math/EuclideanRing.md
similarity index 100%
rename from fp/Class/Math/EuclideanRing.md
rename to fp/Classes/Math/EuclideanRing.md
diff --git a/fp/Class/Math/Ring.md b/fp/Classes/Math/Ring.md
similarity index 100%
rename from fp/Class/Math/Ring.md
rename to fp/Classes/Math/Ring.md
diff --git a/fp/Class/Math/Semiring.md b/fp/Classes/Math/Semiring.md
similarity index 100%
rename from fp/Class/Math/Semiring.md
rename to fp/Classes/Math/Semiring.md
diff --git a/fp/Class/Monoid.md b/fp/Classes/Monoid.md
similarity index 100%
rename from fp/Class/Monoid.md
rename to fp/Classes/Monoid.md
diff --git a/fp/Class/Semigroup.md b/fp/Classes/Semigroup.md
similarity index 100%
rename from fp/Class/Semigroup.md
rename to fp/Classes/Semigroup.md
diff --git a/fp/Class/Show.md b/fp/Classes/Show.md
similarity index 100%
rename from fp/Class/Show.md
rename to fp/Classes/Show.md
diff --git a/fp/Class/Alt.md b/fp/Classes/Traversable.md
similarity index 100%
rename from fp/Class/Alt.md
rename to fp/Classes/Traversable.md
diff --git a/fp/Class/Alternative.md b/fp/Data/Collections/NonEmptyArray.md
similarity index 100%
rename from fp/Class/Alternative.md
rename to fp/Data/Collections/NonEmptyArray.md
diff --git a/fp/Class/Applicative.md b/fp/Data/Collections/NonEmptyList.md
similarity index 100%
rename from fp/Class/Applicative.md
rename to fp/Data/Collections/NonEmptyList.md
diff --git a/fp/Class/Plus.md b/fp/Data/String.md
similarity index 100%
rename from fp/Class/Plus.md
rename to fp/Data/String.md
diff --git a/fp/Language/Infix Operators/Common Operators/Data.md b/fp/Language/Infix Operators/Common Operators/Data.md
index 81a36b2..2bef78f 100644
--- a/fp/Language/Infix Operators/Common Operators/Data.md
+++ b/fp/Language/Infix Operators/Common Operators/Data.md
@@ -1,6 +1,7 @@
|Operator|Description|Associativity|Precedence|Defined As|
|--|--|--|--|--|
|`<>`|append|right|5|[`Data.Semigroup.append`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Semigroup#v:(%3C%3E))|
+|`/\`|Tuple constructor|right|6|[`Data.Tuple.Nested.Tuple`](https://pursuit.purescript.org/packages/purescript-tuples/docs/Data.Tuple.Nested#v:(%2F%5C))|
|`<$>`|map|||
|`<#>`|flipped map|||
|`<*>`|apply (map using function of 2+ arguments)|||
diff --git a/fp/Monads/Transformers/ExceptT.md b/fp/Monads/Transformers/ExceptT.md
new file mode 100644
index 0000000..e69de29
diff --git a/fp/Monads/Transformers/MaybeT.md b/fp/Monads/Transformers/MaybeT.md
new file mode 100644
index 0000000..e69de29
diff --git a/fp/Monads/Transformers/ReaderT.md b/fp/Monads/Transformers/ReaderT.md
new file mode 100644
index 0000000..e69de29
diff --git a/fp/Monads/Transformers/StateT.md b/fp/Monads/Transformers/StateT.md
new file mode 100644
index 0000000..e69de29
diff --git a/fp/Monads/Transformers/WriterT.md b/fp/Monads/Transformers/WriterT.md
new file mode 100644
index 0000000..e69de29