forked from orion/obsidian
update
This commit is contained in:
18
fp/Classes/Functor/Applicative.md
Normal file
18
fp/Classes/Functor/Applicative.md
Normal file
@@ -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`<sup><i>more or less</i></sup>
|
||||
[[Aff]]|`Promise.resolve(a)`<sup><i>more or less</i></sup>
|
||||
79
fp/Classes/Functor/Apply.md
Normal file
79
fp/Classes/Functor/Apply.md
Normal file
@@ -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'
|
||||
```
|
||||
66
fp/Classes/Functor/Functor.md
Normal file
66
fp/Classes/Functor/Functor.md
Normal file
@@ -0,0 +1,66 @@
|
||||
[[Typeclasses|Typeclass]] defining the [[Functions|function]] `map`, [[Infix Operators|operators]] `<$>`, and `<#>`.
|
||||
|
||||
```haskell
|
||||
class Functor f where
|
||||
map :: forall a b. (a -> b) -> f a -> f b
|
||||
```
|
||||
|
||||
## map
|
||||
For a [[Data Structures|data structure]] containing some data `a`, change the data using some function `a -> b`.
|
||||
|
||||
> [!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 ...
|
||||
|
||||
## Examples
|
||||
### [[Array]] of [[Int]]
|
||||
```haskell
|
||||
add 1 <$> [1, 2, 3]
|
||||
-- [2, 3, 4]
|
||||
```
|
||||
|
||||
### [[Maybe]] of [[Int]]
|
||||
```haskell
|
||||
add 1 <$> Just 1
|
||||
-- Just
|
||||
|
||||
add 1 <$> Nothing
|
||||
-- Nothing
|
||||
```
|
||||
|
||||
### [[Effect]] of [[Int]]
|
||||
See also:
|
||||
- [[Bind]]
|
||||
- [[Show]]
|
||||
- [[Functions/Composition|compose]]
|
||||
- [[do notation]]
|
||||
```haskell
|
||||
import Node.FS.Sync (readTextFile, writeTextFile)
|
||||
import Node.Encoding (Encoding(..))
|
||||
import Data.Int as Int
|
||||
|
||||
writeNum :: Int -> Effect Unit
|
||||
writeNum n = writeTextFile "num.txt" (show n) UTF8
|
||||
|
||||
readNum :: Effect Int
|
||||
readNum =
|
||||
readTextFile "num.txt" UTF8
|
||||
>>= (Int.fromString >>> liftMaybe (error "invalid integer"))
|
||||
|
||||
main = do
|
||||
writeNum
|
||||
n <- add 1 <$> readNum
|
||||
log $ show n
|
||||
-- 2
|
||||
```
|
||||
Reference in New Issue
Block a user