fp-course
所属分类:其他
开发工具:Haskell
文件大小:0KB
下载次数:0
上传日期:2023-03-06 02:28:36
上 传 者:
sh-1993
说明: 函数编程课程,
(Functional Programming Course,)
文件列表:
.editorconfig (117, 2021-10-07)
.ghci (311, 2021-10-07)
.travis.yml (5306, 2021-10-07)
CHEATSHEET.md (7856, 2021-10-07)
Setup.lhs (70, 2021-10-07)
Vagrantfile (281, 2021-10-07)
cabal.project (14, 2021-10-07)
changelog (355, 2021-10-07)
ci/ (0, 2021-10-07)
ci/ci.nix (844, 2021-10-07)
ci/jobsets.json (539, 2021-10-07)
ci/jobsets.nix (887, 2021-10-07)
course.cabal (4439, 2021-10-07)
course.lkshf (374, 2021-10-07)
default.nix (1110, 2021-10-07)
etc/ (0, 2021-10-07)
etc/CONTRIBUTORS (1896, 2021-10-07)
etc/LICENCE (1695, 2021-10-07)
fp-course.nix (498, 2021-10-07)
ops/ (0, 2021-10-07)
ops/ansible.yaml (1302, 2021-10-07)
ops/emacs.d/ (0, 2021-10-07)
ops/emacs.d/init.el (1113, 2021-10-07)
ops/haskell.yaml (736, 2021-10-07)
ops/sublime.yaml (586, 2021-10-07)
ops/vs-code.yaml (721, 2021-10-07)
projects/ (0, 2021-10-07)
projects/NetworkServer/ (0, 2021-10-07)
projects/NetworkServer/NetworkServer.markdown (6222, 2021-10-07)
projects/NetworkServer/haskell/ (0, 2021-10-07)
projects/NetworkServer/haskell/.ghci (65, 2021-10-07)
projects/NetworkServer/haskell/Setup.lhs (1963, 2021-10-07)
projects/NetworkServer/haskell/etc/ (0, 2021-10-07)
projects/NetworkServer/haskell/etc/LICENCE (1494, 2021-10-07)
projects/NetworkServer/haskell/network-server.cabal (2964, 2021-10-07)
projects/NetworkServer/haskell/src/ (0, 2021-10-07)
... ...
## Cheatsheet
### Vocabulary
|**Symbol**|**Pronunciation** |**Notes** |
|----------|---------------------|------------------------------------------------|
|`:.` |cons |Adds an element to the front of a list |
|`<$>` |eff-map |Member of the Functor type class |
|`<*>` |app, apply, spaceship|Member of the Applicative type class |
|`>>=` |bind |Member of the Monad type class |
|`bool` |bool |if/then/else with arguments in the reverse order|
### Equivalent expressions
Here are some expressions and their neater, more idiomatic alternatives.
**Function application**
`\x -> f x` may be replaced with `f`
**Composition**
`\x -> f (g x)` may be replaced with `f . g`
### Follow the types
Rather than thinking operationally, focus on finding values for the types that the compiler is telling you you need.
Once you have a compiling program it's easier to look at what you have and decide if it solves your problem.
### Use type holes
Following on from the previous point, use type holes to discover the types of the values you need to
provide. A type hole is an underscore, or a name prefixed by an underscore (`_`). When GHC sees a
type hole, it will produce a compiler error that tells you the type of the value that should be in
its place.
As an example, let's assume we're attempting to write a definition for `List.product` using
`foldRight`, but we're not sure how to apply `foldRight` to get our solution. We can start by adding
some type holes.
```haskell
product ::
List Int
-> Int
product ns =
foldRight _f _n ns
```
We can now reload the course code in GHCi and see what it tells us.
```
λ> :r
[ 5 of 26] Compiling Course.List ( src/Course/List.hs, interpreted )
src/Course/List.hs:95:13: error:
Found hole: _f :: Int -> Int -> Int
Or perhaps ‘_f’ is mis-spelled, or not in scope
In the first argument of ‘foldRight’, namely ‘_f’
In the expression: foldRight _f _n ns
In an equation for ‘product’: product ns = foldRight _f _n ns
Relevant bindings include
ns :: List Int (bound at src/Course/List.hs:94:9)
product :: List Int -> Int (bound at src/Course/List.hs:94:1)
src/Course/List.hs:95:16: error:
Found hole: _n :: Int
Or perhaps ‘_n’ is mis-spelled, or not in scope
In the second argument of ‘foldRight’, namely ‘_n’
In the expression: foldRight _f _n ns
In an equation for ‘product’: product ns = foldRight _f _n ns
Relevant bindings include
ns :: List Int (bound at src/Course/List.hs:94:9)
product :: List Int -> Int (bound at src/Course/List.hs:94:1)
Failed, modules loaded: Course.Core, Course.ExactlyOne, Course.Optional, Course.Validation.
```
GHC is telling us a few helpful things here for each of our holes:
- The type of the hole: `Found hole: _f :: Int -> Int -> Int`
- Where it found the hole:
```
In the first argument of ‘foldRight’, namely ‘_f’
In the expression: foldRight _f _n ns
In an equation for ‘product’: product ns = foldRight _f _n ns
```
- Bindings that are relevant to working out the type of the hole:
```
Relevant bindings include
ns :: List Int (bound at src/Course/List.hs:94:9)
product :: List Int -> Int (bound at src/Course/List.hs:94:1)
```
Armed with this information we now have two smaller sub-problems to solve: choosing a function of
type `Int -> Int -> Int`, and choosing a value of type `Int`.
Keep in mind that this example is just for demonstrating the mechanics of type holes. The pay off
from deploying them increases as the difficulty and complexity of your problem increases, as they
allow you to break your problem into pieces while telling you the type of each piece.
### Use `:type` to ask GHC the type of expressions
If you've forgotten the type of an expression, or want to check if part of a solution type checks
and has the type that you expect, use `:type` or `:t` in GHCi.
```
λ> :t (:.)
(:.) :: t -> List t -> List t
λ> :t (:.) 5
(:.) 5 :: Num t => List t -> List t
λ> :t Nil
Nil :: List t
λ> :t (:.) 5 Nil
(:.) 5 Nil :: Num t => List t
λ> (:.) 5 Nil
[5]
```
### Use `:info` to ask GHC questions
If you ever want to know what an identifier is, you can ask GHCi using `:info` or just `:i`. For
example, if you see `List` somewhere in your code and want to know more about it, enter `:i List` in
GHCi. As shown below, it will print the constructors for values of that type, as well as the
instances for any type classes that are in scope.
```
λ> :i List
data List t = Nil | t :. (List t)
-- Defined at src/Course/List.hs:34:1
instance [safe] Eq t => Eq (List t)
-- Defined at src/Course/List.hs:37:13
instance [safe] Ord t => Ord (List t)
-- Defined at src/Course/List.hs:37:17
instance [safe] Show t => Show (List t)
-- Defined at src/Course/List.hs:42:10
instance [safe] IsString (List Char)
-- Defined at src/Course/List.hs:662:10
instance [safe] Functor List
-- Defined at src/Course/Functor.hs:54:10
instance [safe] Extend List
-- Defined at src/Course/Extend.hs:49:10
instance [safe] Applicative List
-- Defined at src/Course/Applicative.hs:65:10
instance [safe] Monad List -- Defined at src/Course/Monad.hs:46:10
instance [safe] Traversable List
-- Defined at src/Course/Traversable.hs:33:10
```
### Providing functions
If you're ever stuck providing a function as an argument or return value, insert a lambda with a
type hole. Continue this process recursively until you need to provide a simple value, then follow
the definitions back out.
Following on from our type holes example, if we're trying to solve `product` with `foldRight` and we
know the first argument to `foldRight` is a function, start by inserting the lambda.
```haskell
product ::
List Int
-> Int
product ns =
foldRight (\a b -> _c) _n ns
```
After reloading this code, GHCi will tell us the type of `_c`, which in this case is `Int`. From the
previous type hole example, we know that both `a` and `b` are type `Int` (`_f :: Int -> Int ->
Int`), so it looks like we should do something with two `Int`s to produce an `Int`. A few operations
come to mind, but given we're defining `product`, let's go with multiplication.
```haskell
product ns =
foldRight (\a b -> a * b) _n ns
```
It type checks. From here we'd need to pick an `Int` to replace `_n` and we'd have a solution that
at least type checks.
If `_c` had the type of another function, we'd simply insert another lambda in its place and
continue recursing. Alternatively, if `_c` had type `WhoosyWhatsits` and we didn't know anything
about that type or how to construct it, we could just ask GHCi using `:i WhoosyWhatsits` and
continue from there.
### Handling arguments
When you're not sure what to do with a function argument, try pattern matching it and looking at the
values that are brought into scope.
```haskell
data Bar = Bar Chars Int Chars
foo :: Bar -> Int
foo (Bar _ n _) = n
```
If your argument is a sum type that has multiple constructors, use `case` to pattern match and
handle each case individually.
```haskell
data Baz =
C1 Int
| C2 Chars Int
quux :: Baz -> Int
quux baz =
case baz of
C1 n -> n
C2 _ n -> n
```
You can also nest pattern matches as needed.
```haskell
data Thingo =
X Int
| Y (Optional Int)
f :: Thingo -> List Int
f t =
case t of
X n -> n :. Nil
Y (Full n) -> n :. Nil
Y Empty -> Nil
```
Finally, when you're not sure how to pattern match the argument because you don't know what its
constructors are, use `:info` as described above to find out.
```
λ> :i Baz
data Baz = C1 Int | C2 Chars Int
```
近期下载者:
相关文件:
收藏者: