-
Notifications
You must be signed in to change notification settings - Fork 3
/
milewski-programmers-4.jmd
153 lines (110 loc) · 3.78 KB
/
milewski-programmers-4.jmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
### Kleisli Categories
**NOTE: I have decided to skip the Haskell portion of this chapter being Section 4.2 as there was not a full implementation of the Writer Monad and Kleisli Category examples provided.
As I am not an expert in Haskell, I have decided to move forward to focus on the math over Haskell.
If you have an implementation, feel free to open a PR on this repo!**
> What is an example of a non-pure function?
```julia
global logger = ""
function negate(x::Bool)
global logger = "Negated!"
return !x
end
```
This function also modifies `logger` as a side effect and as such `negate` is a non-pure function.
> What is the Writer Category?
The Writer Category is a category that allows one to track the execution of functions.
> What are examples of the Writer Category involving Strings?
```julia
function toUpper(str::String)::Vector{Union{String, String}}
return [uppercase(str), "toUpper "]
end
```
```julia
words(w::String)::Vector{Union{Vector{String}, String}} = [string.(split(w)), "toWords "]
toWords(w::String)::Vector{Union{Vector{String}, String}} = words(w)
```
```julia
function process(sentence::String)::Vector{Union{Vector{String}, String}}
p1 = toUpper(sentence)
p2 = toWords(first(p1))
return [first(p2), p1[2] .* p2[2]]
end
```
> What are examples of the Writer Category involving Numerics?
```julia
isEven(x::Int)::Vector{Union{Bool, String}} = [x % 2 == 0, "isEven "]
negate(x::Bool)::Vector{Union{Bool, String}} = [!x, "Negated "]
```
```julia
function isOdd(x::Int)::Vector{Union{Bool,String}}
p1 = isEven(x)
p2 = negate(first(p1))
return [p2[1], p1[2] * p2[2]]
end
```
> What is a generic composition function of the Writer Category?
```julia
function compose(f::Function, g::Function)
function _compose(x; f = f, g = g)
p1 = f(x)
p2 = g(p1[1])
return [p2[1], p1[2] * p2[2]]
end
end
```
> What is a generic identity function of the Writer Category?
```julia
function identity(x)
return [x, ""]
end
```
> What are Kleisli Categories?
A working definition is that it is a category that has as objects the types of the underlying programming language.
> What are the characteristics of Kleisli Categories?
- It is based on the _writer monad_
- Its objects are the types of an programming language
- Kleisli categories define their own compositions
> What are examples of morphisms in the Kleisli Category?
An arrow from some type $A$ to some type derived from $B$.
> What is a Writer Monad?
A writer monad is used for logging or tracing the execution of functions.
General process to embed effects in pure computations.
> What do Writer Monads do?
They log or trace the execution of functions as well as execute a procedure.
> What is a partial function?
A function that is not defined for all possible values of its argument.
### Challenge
1. Construct the Kleisli category for partial functions (define composition and identity).
```julia
function compose(f::Function, g::Function)
function _compose(x; f = f, g = g)
p1 = f(x)
p2 = g(p1[1])
return [p2[1], p1[2] * p2[2]]
end
end
```
```julia
function identity(x)
return [x[1], "" * x[2]]
end
```
2. Implement the embellished function `safe_reciprocal` that returns a valid reciprocal of its argument, if it’s different from zero.
```julia
function safe_reciprocal(x)
x != 0.0 ? [1.0 / x, "Safe Reciprocal "] : [Real[], "Safe Reciprocal "]
end
```
3. Compose the functions `safe_root` and `safe_reciprocal` to implement `safe_root_reciprocal` that calculates `sqrt(1/x)` whenever possible.
```julia
function safe_root(x)
x >= 0.0 ? [sqrt(x), "Safe Root "] : [Real[], "Safe Root "]
end
```
```julia
function safe_root_reciprocal(x)
p1 = safe_root(x)
p2 = identity(safe_reciprocal(p1[1]))
return [p2[1], p1[2] * p2[2]]
end
```