- functor 是实现
`Functor`

typeclass 的数据类型 - applicative 是实现
`Applicative`

typeclass 的数据类型 - monad 是实现
`Monad`

typeclass 的数据类型 `Maybe`

实现了所有它们三个，因此同时是 functor、applicative，和 monad

– 图解 Functor、Applicative、Monad, Aditya Bhargava.

- 可以被 map over 的对象，是一个 typeclass。

`fmap :: (a -> b) -> f a -> f b`

`fmap`

是这个 typeclass (`Functor`

类) 中唯一被定义的函数。我们可以把`fmap`

当做某种 lifting function，**接受一个参数为普通值 a -> b 的函数并把它提升为一个参数为容器 f a -> f b 的函数** (接受 function 并回传一个新的 function 的 function，回传的 function 接受一个 functor 并回传一个 functor)。

```
> :t fmap (*2)
ghcifmap (*2) :: (Num a, Functor f) => f a -> f a
> :t fmap (replicate 3)
ghcifmap (replicate 3) :: (Functor f) => f a -> f [a]
```

- 中缀符为
`<$>`

- preserve identity:
`fmap id = id`

- composable:
`fmap f . fmap g = fmap (f . g)`

(把两个`fmap`

组合使用效果应该和把函数组合起来再用`fmap`

相同)

- 如果一个类型有且仅有一个类型参数，我们才能给它 实现
`Functor`

实例。 因此，我们不能给`Either a b`

或者`(a, b)`

写`fmap`

实现，因为它们有两个类型参数。我们也不能 给`Bool`

或者`Int`

写，因为它们没有类型参数。 - 我们不能给类型定义添加任何约束。

Monads and Effects, 4

- [Wad92a] P. Wadler. Comprehending monads.
- [Wad92b] P. Wadler. The essence of functional programming.
- [Wad95] P. Wadler. Monads for functional programming.

The representation of monads in Haskell is based on the *Kleisli triple* formulation:

A

Kleisli tripleover a categroy 𝒞 is a triple (T,η,_{−}^{*}), whereT: |𝒞| → |𝒞|,η_{A}:A→TAforA∈ |𝒞|,f^{*}:TA→TBforf:A→TBand the following equation hold: . . .

In Haskell, 𝒞 is the categroy which Haskell types as objects and Haskell functions as arrows, *T* corresponds to a parameterised type, *η* is called `return`

, and _{−}^{*} is called `>>==`

```
return :: a -> T a
(>>=) :: (a -> T b) -> (T a -> T b)
```

In Haskell,

`return`

is used to wrap data in amonad. When speaking about I/O,`return`

is used to take pure data and bring it into the IO monad.

–Real World Haskell, Chapter 7, I/O, The IO MonadA useful way to link its behavior to its name is that it

injects(returns) a pure value (of type`a`

) into a monad (of type`m a`

).

–Real World Haskell, Chapter 14, Monads, The Monad Typeclass

We can consider `>>=`

to be a currried function of *two* arguments, with type `(a -> T b)`

and `T a`

.

We give `>>=`

the type

`(>>=) :: T a -> (a -> T b) -> T b`

Now the metalanguage notation let *x* ⇐ *e*_{1} in *e*_{2} can be conveniently expressed as:

`>>= \x -> e2 e1 `

`\x -> e`

means*λ*xe- this bind
`x`

to the result of`e1`

in`e2`

; `>>=`

pronounced as “bind”`\x`

pronounced as “*λ*x”

This is Anonymous (lambda) function in Haskell. We introduce an anonymous function with a backslash character (

`\`

) pronouncedlambda. (the backslash was chosen for its visual resemblance to the Greek letterλ.)

–Real World Haskell, Chapter 4, Functional Programming, Anonymous (lambda) Functions

**November 22, 2022**, tags: monad, type system.

*Monads* and *comonads* (the dual of monads) are closely related to adjunctions (Kleisli and Eilenberg-Moore), probably the most pervasive notion in Category Theory.

We intend to use monads for giving denotational semantics to programming languages, and more specifically as a way of modeling *computational types*.

in [Mog91] *Notions of Computation and Monads*:

The basic idea behind the categorical semantics below is that, in order to interpret a programming language in Category 𝒞, we distinguish the object

Aof values (of typeA) from the objectTAof computations (of typeA), and take as denotations of programs (of typeA) theelementsofTA. In particular, we identify the typeAwith the object of values (of typeA) and obtain the object of computations (of typeA) by applying an unary type-constructorTtoA. We callTanotion of computation, since it abstracts away from the type of values computations may produce.

**Example 1**. We give few notions of computation in the Category of sets.

- partiality:
*T**A*=*A*_{⊥}, i.e.*A*+ { ⊥ }. (⊥is the*diverging computation*) - nondeterminism:
*T**A*= 𝒫_{fin}(*A*), i.e. the set of finite subsets of*A*. - side-effects:
*T**A*= (*A*×*S*)^{S}, where*S*is a set of states, e.g. a set*U*^{L}of stores or a set of input/output sequences*U*^{*} - exceptions:
*T**A*=*A*+*E*, where*E*is the set of exceptions - continuations:
*T**A*=*R*^{RA}, where*R*is the set of results - interactive input:
*T**A*= (*μ**X***.***A*+*X*^{U}), where*U*is the set of characters. - interactive output:
*T**A*= (*μ**X***.***A*+(*U*×*X*)), i.e.*U*^{*}×*A*up to iso.

**November 22, 2022**, tags: computation.

In computer science, a computation is said to diverge if it does not terminate or terminates in an exceptional state. Otherwise it is said to converge.

In the *λ*-calculus an expression is *divergent* if it has no normal form.

In *denotational semantics* an object function *f* : *A* → *B* can be modelled as a mathematical function *f* : *A* ∪ { ⊥ } → *B* ∪ { ⊥ } where ⊥ indicates that the object function or its argument *diverges*.

**November 19, 2022**, tags: type system.

Types first appeared in Principia Mathematica, Whitehead and Russell [1910-1913].

In *Functionality in Combinatory Logic* of H. B. Curry:

For a theory concerned with an analysis of these notions I have proposed the name

combinatory logic. This is a formal theory based on a primitive frame (i.e., set of primitive ideas, axioms and rules of procedure) of such great simplicity that even comparatively simple inferences, such as are ordinarily made by a substitution process can be decomposed into a large number of the elemental steps represented by the rules of procedure; it furthermore does not postulate any such notions as variable, although all the inferences ordinarily made by the use of variables can-when suitable definitions have been made, of course-be made as compound inferences within the system. The development of this theory, to the point where these statements relative to variables can be proved, is contained in a series of papers culminating in “Apparent Variables from the Standpoint of Combinatory Logic” (Ann. M1lath., 2nd ser., 34, 381-404 (1933)).

We are concerned with statements of the form (using E. H. Moore’s terminology) “

fis a function onXtoY”; or (for functions of several variables) “fis a function onX_{1}X_{2}…X_{m}toY.” The following type of question suggests itself: Suppose we have given certain entitiesf_{1},f_{2}, …,f_{n}concerning each of which a statement of the above form has been made; suppose further thatgis an entity derived fromf_{1}, …,f_{n}by substitution or other such processes; then, what statement of the above form can we infer concerningg? We make inferences of the above form intuitively;what this paper asserts is that when certain formal constituents are added to the primitive frame of combinatory logic, then these inferences can be made abstractly within the extended system.

In Curry and Feys [1958] this type assignment mechanism was adapted to λ-terms.

In Church [1940] *l**a**m**b**d**a*-terms were ornamented by fixed types.

*M*of type*A*can be an argument only of a function of type*A*→*B*.`(real → real) → (real → real)`

for indefinite integrals ∫*f*(*x*)*d**x*;`(real → real) × real × real → real`

for definite integrals ∫_{a}^{b}*f*(*x*)*d**x*;`([0, 1] → real) → (([0, 1] → real) → real) → (([0, 1] → real) → real)`

decides whether an untyped term does have a type and computes the most general type types found their way to functional programming languages.

It was first implemented as part of the type system (simply typed *λ*-calculus) of the programming language ML. (Milner, Tofte, Harper, and McQueen [1997])

In type theory, a type system has the property of subject reduction (also subject evaluation, type preservation or simply preservation) if evaluation of expressions does not cause their type to change.

if a term *M* is correctly typed by type *A*, then also during the computation of *M* the type remains the same.

Barendregt H, Dekkers W, Statman R. Lambda calculus with types[M]. Cambridge University Press, 2013.

http://hopl.info/showstructure.prx?structureid=41

The input *M* becomes part of an expression *F**M* to be evaluated, where *F* represents the intended function to be computed on *M*.

a short functional program generating primes using Eratosthenes sieve (Miranda program by D. Turner):

```
primes = sieve [2..]
where
sieve (p:x) = p : sieve [n | n<-x ; n mod p > 0]
primes_upto n = [p | p<- primes ; p<n]
```

in Haskell (from rosettacode.org):

```
{-# LANGUAGE FlexibleContexts #-} -- too lazy to write contexts...
{-# OPTIONS_GHC -O2 #-}
import Control.Monad.ST ( runST, ST )
import Data.Array.Base ( MArray(newArray, unsafeRead, unsafeWrite),
IArray(unsafeAt),
STUArray, unsafeFreezeSTUArray, assocs )
import Data.Time.Clock.POSIX ( getPOSIXTime ) -- for timing...
primesTo :: Int -> [Int] -- generate a list of primes to given limit...
= runST $ do
primesTo limit let lmt = limit - 2-- raw index of limit!
<- newArray (2, limit) False -- when indexed is true is composite
cmpsts <- unsafeFreezeSTUArray cmpsts -- frozen in place!
cmpstsf let getbpndx bp = (bp, bp * bp - 2) -- bp -> bp, raw index of start cull
= unsafeWrite cmpsts i True -- cull composite by raw ndx
cullcmpst i = mapM_ cullcmpst [ si0, si0 + bp .. lmt ]
cull4bpndx (bp, si0) mapM_ cull4bpndx
$ takeWhile ((>=) lmt . snd) -- for bp's <= square root limit
| (bp, False) <- assocs cmpstsf ]
[ getbpndx bp return [ p | (p, False) <- assocs cmpstsf ] -- non-raw ndx is prime
-- testing...
main :: IO ()
= do
main putStrLn $ "The primes up to 100 are " ++ show (primesTo 100)
putStrLn $ "The number of primes up to a million is " ++
show (length $ primesTo 1000000)
let top = 1000000000
<- getPOSIXTime
start let answr = length $ primesTo top
<- answr `seq` getPOSIXTime -- force result for timing!
stop let elpsd = round $ 1e3 * (stop - start) :: Int
putStrLn $ "Found " ++ show answr ++ " to " ++ show top ++
" in " ++ show elpsd ++ " milliseconds."
```

in Scheme:

```
; Tail-recursive solution :
define (sieve n)
(define (aux u v)
(let ((p (car v)))
(if (> (* p p) n)
(let rev-append ((u u) (v v))
(if (null? u) v (rev-append (cdr u) (cons (car u) v))))
(cons p u)
(aux (let wheel ((u '()) (v (cdr v)) (a (* p p)))
(cond ((null? v) (reverse u))
(= (car v) a) (wheel u (cdr v) (+ a p)))
((> (car v) a) (wheel u v (+ a p)))
((else (wheel (cons (car v) u) (cdr v) a))))))))
(2)
(aux '(let range ((v '()) (k (if (odd? n) n (- n 1))))
(if (< k 3) v (range (cons k v) (- k 2))))))
(
; > (sieve 100)
; (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)
; > (length (sieve 10000000))
; 664579
; Simpler solution, with the penalty that none of 'iota, 'strike or 'sieve is tail-recursive :
define (iota start stop stride)
(if (> start stop)
(list)
(cons start (iota (+ start stride) stop stride))))
(
define (strike lst start stride)
(cond ((null? lst) lst)
(= (car lst) start) (strike (cdr lst) (+ start stride) stride))
((> (car lst) start) (strike lst (+ start stride) stride))
((else (cons (car lst) (strike (cdr lst) start stride)))))
(
define (primes limit)
(let ((stop (sqrt limit)))
(define (sieve lst)
(let ((p (car lst)))
(if (> p stop)
(
lstcons p (sieve (strike (cdr lst) (* p p) p))))))
(2 limit 1))))
(sieve (iota
display (primes 100))
(newline)
(
; (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)
```

an *imperative language* looks like (Java program from rosettacode.org)

```
import java.util.LinkedList;
import java.util.BitSet;
public class Sieve{
public static LinkedList<Integer> sieve(int n){
LinkedList<Integer> primes = new LinkedList<Integer>();
BitSet nonPrimes = new BitSet(n+1);
for (int p = 2; p <= n ; p = nonPrimes.nextClearBit(p+1)) {
for (int i = p * p; i <= n; i += p)
.set(i);
nonPrimes.add(p);
primes}
return primes;
}
}
```

The power of functional programming languages derives from several facts.

- referential transparency: All expressions of a functional programming language have a constant meaning (i.e. independent of a hidden state)
- functionals / higher order functions: Functions may be arguments of other functions
- clear goal-directed mathematical way: Algorithms can be expressed in a clear goal-directed mathematical way, using various forms of recursion and flexible data structures. The bookkeeping needed for the storage of these values is handled by the language
**compiler**instead of the user.