[2024] An Introduction to Functional Programming with Go [Y Combinator Remix].pdf
feyeleanor
35 views
117 slides
Oct 07, 2024
Slide 1 of 156
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
154
155
156
About This Presentation
A reworking of my 2019 GoLab Keynote on Functional Programming in Go, updated to embrace Go Generics.
Now with added Y Combinator goodness including the generically typed Y Combinator with automatic Memoisation, a world first in Go.
Don't settle for the rest - be baffled by the best :)
Code a...
A reworking of my 2019 GoLab Keynote on Functional Programming in Go, updated to embrace Go Generics.
Now with added Y Combinator goodness including the generically typed Y Combinator with automatic Memoisation, a world first in Go.
Don't settle for the rest - be baffled by the best :)
Code available at https://github.com/feyeleanor/intro_to_fp_in_go
Video at https://www.youtube.com/watch?v=b8WH2107Uh0
Size: 11.59 MB
Language: en
Added: Oct 07, 2024
Slides: 117 pages
Slide Content
AN
INTRODUCTION
TO
FUNCTIONAL PROGRAMMING
IN
GO [Y COMBINATOR REMIX]
ELEANOR MCHUGH
ELEANOR M
C
HUGH
@feyeleanor
MISAPPLIED PHYSICIST
EMBEDDED SYSTEMS
VIRTUAL MACHINES
P2P NETWORKING
DIGITAL IDENTITY
SECURE COMMS
JAVASCRIPT
RUBY
GO
OO makes code understandable by
encapsulating moving parts.
FP makes code understandable by
minimizing moving parts.
Michael Feathers
@mfeathers
AN INTRODUCTION TO FUNCTIONAL PROGRAMMING IN GO [Y COMBINATOR REMIX]
LEANPUB://GONOTEBOOK
FUNCTIONS
AS
PARADIGM
FUNCTIONS
AS
PARADIGM
A PURE FUNCTION
A PURE FUNCTION
package main
import "os"
func main() {
os.Exit(add(3, 4))
}
func add(x, y int) int {
return x + y
}
50.GO
A PURE FUNCTION
package main
import "os"
func main() {
os.Exit(add(3, 4))
}
func add(x, y int) int {
return x + y
}
50.GO
A PURE FUNCTION
package main
import "os"
func main() {
os.Exit(add(3, 4))
}
func add(x int, y int) int {
return x + y
}
50.GO
A PURE FUNCTION
package main
import "os"
func main() {
os.Exit(add(3, 4))
}
func add(x int, y int) int {
return x + y
}
50.GO
A PURE FUNCTION
package main
import "os"
func main() {
os.Exit(add(3, 4))
}
func add(x int, y int) int {
return x + y
}
50.GO
A PURE FUNCTION
func main() {
os.Exit(add(3, 4))
}
type Scalar interface {
int | int8 | int16 | int32 | int64 |
uint | uint8 | uint16 | uint32 | uint64 |
float32 | float64
}
func add[T Scalar](x, y T) T {
return x + y
}
51.GO
A PURE FUNCTION
func main() {
os.Exit(add(3, 4))
}
type Scalar interface {
int | int8 | int16 | int32 | int64 |
uint | uint8 | uint16 | uint32 | uint64 |
float32 | float64
}
func add[T Scalar](x, y T) T {
return x + y
}
51.GO
A PURE FUNCTION
func main() {
os.Exit(add(3, 4))
}
type Scalar interface {
int | int8 | int16 | int32 | int64 |
uint | uint8 | uint16 | uint32 | uint64 |
float32 | float64
}
func add[T Scalar](x, y T) T {
return x + y
}
51.GO
A PURE FUNCTION
package main
import "os"
import "strconv"
func main() {
x, _ := strconv.Atoi(os.Args[1])
y, _ := strconv.Atoi(os.Args[2])
os.Exit(add(x, y))
}
type Scalar interface {
int | int8 | int16 | int32 | int64 |
uint | uint8 | uint16 | uint32 | uint64 |
float32 | float64
}
func add[T Scalar](x, y T) T {
return x + y
}
52.GO
A PURE FUNCTION
package main
import "os"
import "strconv"
func main() {
x, _ := strconv.Atoi(os.Args[1])
y, _ := strconv.Atoi(os.Args[2])
os.Exit(add(x, y))
}
type Scalar interface {
int | int8 | int16 | int32 | int64 |
uint | uint8 | uint16 | uint32 | uint64 |
float32 | float64
}
func add[T Scalar](x, y T) T {
return x + y
}
52.GO
A PURE FUNCTION
package main
import "os"
import "strconv"
func main() {
x, _ := strconv.Atoi(os.Args[1])
y, _ := strconv.Atoi(os.Args[2])
os.Exit(add(x, y))
}
type Scalar interface {
int | int8 | int16 | int32 | int64 |
uint | uint8 | uint16 | uint32 | uint64 |
float32 | float64
}
func add[T Scalar](x, y T) T {
return x + y
}
52.GO
A PURE FUNCTION
func main() {
os.Exit(add(arg(0), arg(1)))
}
func arg(n int) (r int) {
r, _ = strconv.Atoi(os.Args[n + 1])
return
}
func add[T Scalar](x, y T) T {
return x + y
}
53.GO
A PURE FUNCTION
func main() {
os.Exit(add(arg(0), arg(1)))
}
func arg(n int) (r int) {
r, _ = strconv.Atoi(os.Args[n + 1])
return
}
func add[T Scalar](x, y T) T {
return x + y
}
53.GO
A PURE FUNCTION
func main() {
os.Exit(add(arg(0), arg(1)))
}
func arg(n int) (r int) {
r, _ = strconv.Atoi(os.Args[n + 1])
return
}
func add[T Scalar](x, y T) T {
return x + y
}
53.GO
A PURE FUNCTION
func main() {
os.Exit(add(arg(0), arg(1)))
}
func arg(n int) (r int) {
r, _ = strconv.Atoi(os.Args[n + 1])
return
}
func add[T Scalar](x, y T) T {
return x + y
}
53.GO
A PURE FUNCTION
func main() {
var sum int
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
sum = add(sum, x)
}
os.Exit(sum)
}
func add[T Scalar](x, y T) T {
return x + y
}
54.GO
A PURE FUNCTION
func main() {
var sum int
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
sum = add(sum, x)
}
os.Exit(sum)
}
func add[T Scalar](x, y T) T {
return x + y
}
54.GO
A PURE FUNCTION
func main() {
var sum int
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
sum = add(sum, x)
}
os.Exit(sum)
}
func add[T Scalar](x, y T) T {
return x + y
}
54.GO
A PURE FUNCTION
func main() {
var sum int
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
sum = add(sum, x)
}
os.Exit(sum)
}
func add[T Scalar](x, y T) T {
return x + y
}
54.GO
FUNCTIONS
AS
PARADIGM
FUNCTIONS WITH SIDE-EFFECTS
FUNCTIONS WITH SIDE-EFFECTS
func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
accumulate(x)
}
os.Exit(y)
}
var y int
func accumulate(x int) {
y += x
}
55.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
accumulate(x)
}
os.Exit(y)
}
var y int
func accumulate(x int) {
y += x
}
55.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
accumulate(x)
}
os.Exit(y)
}
var y int
func accumulate(x int) {
y += x
}
55.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
accumulate(x)
}
os.Exit(y)
}
var y int
func accumulate(x int) {
y += x
}
55.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
accumulate(x)
}
os.Exit(y)
}
var y int
func accumulate(x int) {
y += x
}
55.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a.Add(x)
}
os.Exit(int(a))
}
var a Accumulator
type Accumulator int
func (a *Accumulator) Add(y int) {
*a += Accumulator(y)
}
56.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a.Add(x)
}
os.Exit(int(a))
}
var a Accumulator
type Accumulator int
func (a *Accumulator) Add(y int) {
*a += Accumulator(y)
}
56.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a.Add(x)
}
os.Exit(int(a))
}
var a Accumulator
type Accumulator int
func (a *Accumulator) Add(y int) {
*a += Accumulator(y)
}
56.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a.Add(x)
}
os.Exit(int(a))
}
var a Accumulator
type Accumulator int
func (a *Accumulator) Add(y int) {
*a += Accumulator(y)
}
56.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a.Add(x)
}
os.Exit(int(a))
}
var a Accumulator
type Accumulator int
func (a Accumulator) Add(y int) {
a += Accumulator(y)
}
56.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
a := MakeAccumulator[int]()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}
type Accumulator[T Scalar] func(T) T
func MakeAccumulator[T Scalar]() Accumulator[T] {
var y T
return func(x T) T {
y += x
return y
}
}
59.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
a := MakeAccumulator[int]()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}
type Accumulator[T Scalar] func(T) T
func MakeAccumulator[T Scalar]() Accumulator[T] {
var y T
return func(x T) T {
y += x
return y
}
}
59.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
a := MakeAccumulator [int]()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}
type Accumulator[T Scalar] func(T) T
func MakeAccumulator[T Scalar]() Accumulator[T] {
var y T
return func(x T) T {
y += x
return y
}
}
59.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
a := MakeAccumulator[int]()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}
type Accumulator[T Scalar] func(T) T
func MakeAccumulator[T Scalar]() Accumulator[T] {
var y T
return func(x T) T {
y += x
return y
}
}
59.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
a := MakeAccumulator[int]()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}
type Accumulator[T Scalar] func(T) T
func MakeAccumulator[T Scalar]() Accumulator[T] {
var y T
return func(x T) T {
y += x
return y
}
}
59.GO
FUNCTIONS WITH SIDE-EFFECTS
func main() {
a := MakeAccumulator[int]()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}
type Accumulator[T Scalar] func(T) T
func MakeAccumulator[T Scalar]() Accumulator[T] {
var y T
return func(x T) T {
y += x
return y
}
}
59.GO
FUNCTIONS
AS
PARADIGM
FUNCTIONS AS OBJECTS
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a.Int())
}
type Accumulator[T Scalar] func(T) T
func MakeAccumulator[T Scalar]() Accumulator[T] {
var y T
return func(x T) T {
y += x
return y
}
}
func (a Accumulator[T]) Int() int {
return int(a(0))
}
61.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a.Int())
}
type Accumulator[T Scalar] func(T) T
func MakeAccumulator[T Scalar]() Accumulator[T] {
var y T
return func(x T) T {
y += x
return y
}
}
func (a Accumulator[T]) Int() int {
return int(a(0))
}
61.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a.Int())
}
type Accumulator[T Scalar] func(T) T
func MakeAccumulator[T Scalar]() Accumulator[T] {
var y T
return func(x T) T {
y += x
return y
}
}
func (a Accumulator[T]) Int() int {
return int(a(0))
}
61.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
func MakeAccumulator[T Scalar](s ...T) (a Accumulator[T]) {
var y T
a = func(x T) T {
y += x
return y
}
for _, v := range s {
a.Add(v)
}
return
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Accumulator[T]:
a(x(0))
}
return a
}
63.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
func MakeAccumulator[T Scalar](s ...T) (a Accumulator[T]) {
var y T
a = func(x T) T {
y += x
return y
}
for _, v := range s {
a.Add(v)
}
return
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Accumulator[T]:
a(x(0))
}
return a
}
63.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
func MakeAccumulator[T Scalar](s ...T) (a Accumulator[T]) {
var y T
a = func(x T) T {
y += x
return y
}
for _, v := range s {
a.Add(v)
}
return
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Accumulator[T]:
a(x(0))
}
return a
}
63.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
func MakeAccumulator[T Scalar](s ...T) (a Accumulator[T]) {
var y T
a = func(x T) T {
y += x
return y
}
for _, v := range s {
a.Add(v)
}
return
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Accumulator[T]:
a(x(0))
}
return a
}
63.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
func MakeAccumulator[T Scalar](s ...T) (a Accumulator[T]) {
var y T
a = func(x T) T {
y += x
return y
}
for _, v := range s {
a.Add(v)
}
return
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Accumulator[T]:
a(x(0))
}
return a
}
63.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
func MakeAccumulator[T Scalar](s ...T) (a Accumulator[T]) {
var y T
a = func(x T) T {
y += x
return y
}
for _, v := range s {
a.Add(v)
}
return
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Accumulator[T]:
a(x(0))
}
return a
}
63.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
type Integer interface {
Int() int
}
func (a Accumulator[T]) Int() int {
return int(a(0))
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Integer:
a(T(x.Int()))
}
return a
}
64.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
type Integer interface {
Int() int
}
func (a Accumulator[T]) Int() int {
return int(a(0))
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Integer:
a(T(x.Int()))
}
return a
}
64.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
type Integer interface {
Int() int
}
func (a Accumulator[T]) Int() int {
return int(a(0))
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Integer:
a(T(x.Int()))
}
return a
}
64.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
type Integer interface {
Int() int
}
func (a Accumulator[T]) Int() int {
return int(a(0))
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Integer:
a(T(x.Int()))
}
return a
}
64.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
type Integer interface {
Int() int
}
func (a Accumulator[T]) Int() int {
return int(a(0))
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Integer:
a(T(x.Int()))
}
return a
}
64.GO
FUNCTIONS AS OBJECTS
func main() {
a := MakeAccumulator[int]()
for i, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a = a.Add(x).Add(MakeAccumulator(i))
}
os.Exit(a.Int())
}
type Integer interface {
Int() int
}
func (a Accumulator[T]) Int() int {
return int(a(0))
}
func (a Accumulator[T]) Add(x any) Accumulator[T] {
switch x := x.(type) {
case T:
a(x)
case Integer:
a(T(x.Int()))
}
return a
}
64.GO
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %v", x, Factorial(x))
}
type Integer interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
}
func Factorial[T Integer](n T) (r T) {
r = 1
switch {
case n < 0:
panic(n)
case n > 0:
for ; n > 0; n-- {
r *= n
}
}
return
}
72.GO
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %v", x, Factorial(x))
}
type Integer interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
}
func Factorial[T Integer](n T) (r T) {
r = 1
switch {
case n < 0:
panic(n)
case n > 0:
for ; n > 0; n-- {
r *= n
}
}
return
}
72.GO
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %v", x, Factorial(x))
}
type Integer interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
}
func Factorial[T Integer](n T) (r T) {
r = 1
switch {
case n < 0:
panic(n)
case n > 0:
for ; n > 0; n-- {
r *= n
}
}
return
}
72.GO
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %v", x, Factorial(x))
}
type Integer interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
}
func Factorial[T Integer](n T) (r T) {
r = 1
switch {
case n < 0:
panic(n)
case n > 0:
for ; n > 0; n-- {
r *= n
}
}
return
}
72.GO
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %v", x, Factorial(x))
}
type Integer interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
}
func Factorial[T Integer](n T) (r T) {
r = 1
switch {
case n < 0:
panic(n)
case n > 0:
for ; n > 0; n-- {
r *= n
}
}
return
}
72.GO
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %v", x, Factorial(x))
}
type Integer interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
}
func Factorial[T Integer](n T) (r T) {
r = 1
switch {
case n < 0:
panic(n)
case n > 0:
for ; n > 0; n-- {
r *= n
}
}
return
}
72.GO
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %v", x, Factorial(x))
}
type Integer interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
}
func Factorial[T Integer](n T) (r T) {
r = 1
switch {
case n < 0:
panic(n)
case n > 0:
for ; n > 0; n-- {
r *= n
}
}
return
}
72.GO
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %v", x, Factorial(x))
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
73.GO
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %v", x, Factorial(x))
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
73.GO
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %v", x, Factorial(x))
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
73.GO
FUNCTIONS
IN
MATHEMATICS
PAINFUL EXCEPTIONS
PAINFUL EXCEPTIONS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e == nil {
fmt.Printf("%v!: %v", x, Factorial(x))
} else {
panic(v)
}
}
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
74.GO
PAINFUL EXCEPTIONS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e == nil {
fmt.Printf("%v!: %v", x, Factorial(x))
} else {
panic(v)
}
}
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
74.GO
PAINFUL EXCEPTIONS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e == nil {
fmt.Printf("%v!: %v", x, Factorial(x))
} else {
panic(v)
}
}
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
74.GO
PAINFUL EXCEPTIONS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e == nil {
fmt.Printf("%v!: %v", x, Factorial(x))
} else {
panic(v)
}
}
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
74.GO
PAINFUL EXCEPTIONS
func main() {
for _, v := range os.Args[1:] {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v", x, Factorial(x))
} else {
panic(v)
}
}
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
75.GO
PAINFUL EXCEPTIONS
func main() {
for _, v := range os.Args[1:] {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v", x, Factorial(x))
} else {
panic(v)
}
}
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
75.GO
PAINFUL EXCEPTIONS
func main() {
for _, v := range os.Args[1:] {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v", x, Factorial(x))
} else {
panic(v)
}
}
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
75.GO
PAINFUL EXCEPTIONS
func main() {
for _, v := range os.Args[1:] {
func() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
if x, e := strconv.Atoi(v); e == nil {
fmt.Printf("%v!: %v", x, Factorial(x))
} else {
panic(v)
}
}()
}
}
func Factorial[T Integer](n T) (r T) {
if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
76.GO
FUNCTIONS
IN
MATHEMATICS
HIGHER ORDER FUNCTIONS
HIGHER ORDER FUNCTIONS
func main() {
var errors int
computeFactorial := ForValidValues(
func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
errors++
}
})
for _, v := range os.Args[1:] {
computeFactorial(v)
}
os.Exit(errors)
}
func ForValidValues[T Integer](f func(T), e func()) func(string) {
return func(v string) {
defer e()
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
79.GO
HIGHER ORDER FUNCTIONS
func main() {
var errors int
computeFactorial := ForValidValues(
func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
errors++
}
})
for _, v := range os.Args[1:] {
computeFactorial(v)
}
os.Exit(errors)
}
func ForValidValues[T Integer](f func(T), e func()) func(string) {
return func(v string) {
defer e()
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
79.GO
HIGHER ORDER FUNCTIONS
func main() {
var errors int
computeFactorial := ForValidValues(
func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
errors++
}
})
for _, v := range os.Args[1:] {
computeFactorial(v)
}
os.Exit(errors)
}
func ForValidValues[T Integer](f func(T), e func()) func(string) {
return func(v string) {
defer e()
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
79.GO
HIGHER ORDER FUNCTIONS
func main() {
var errors int
computeFactorial := ForValidValues(
func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
errors++
}
})
for _, v := range os.Args[1:] {
computeFactorial(v)
}
os.Exit(errors)
}
func ForValidValues[T Integer](f func(T), e func()) func(string) {
return func(v string) {
defer e()
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
79.GO
HIGHER ORDER FUNCTIONS
func main() {
var errors int
computeFactorial := ForValidValues(
func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
errors++
}
})
for _, v := range os.Args[1:] {
computeFactorial(v)
}
os.Exit(errors)
}
func ForValidValues[T Integer](f func(T), e func()) func(string) {
return func(v string) {
defer e()
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
79.GO
FUNCTIONS
IN
MATHEMATICS
CURRYING AND COMBINATORS
CURRYING
CURRYING AND COMBINATORS
func main() {
printErrors := IfPanics(PrintErrorMessage)
for _, v := range os.Args[1:] {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
}
}
func ValidInteger[T Integer](v string, f func(i T)) func() {
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
func IfPanics(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
func PrintErrorMessage() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
}
}
82.GO
CURRYING AND COMBINATORS
func main() {
printErrors := IfPanics(PrintErrorMessage)
for _, v := range os.Args[1:] {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
}
}
func ValidInteger[T Integer](v string, f func(i T)) func() {
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
func IfPanics(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
func PrintErrorMessage() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
}
}
82.GO
CURRYING AND COMBINATORS
func main() {
printErrors := IfPanics(PrintErrorMessage)
for _, v := range os.Args[1:] {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
}
}
func ValidInteger[T Integer](v string, f func(i T)) func() {
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
func IfPanics(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
func PrintErrorMessage() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
}
}
82.GO
CURRYING AND COMBINATORS
func main() {
printErrors := IfPanics(PrintErrorMessage)
for _, v := range os.Args[1:] {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
}
}
func ValidInteger[T Integer](v string, f func(i T)) func() {
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
func IfPanics(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
func PrintErrorMessage() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
}
}
82.GO
CURRYING AND COMBINATORS
func main() {
printErrors := IfPanics(PrintErrorMessage)
for _, v := range os.Args[1:] {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
}
}
func ValidInteger[T Integer](v string, f func(i T)) func() {
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
func IfPanics(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
func PrintErrorMessage() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
}
}
82.GO
CURRYING AND COMBINATORS
func main() {
printErrors := IfPanics(PrintErrorMessage)
for _, v := range os.Args[1:] {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
}
}
func ValidInteger[T Integer](v string, f func(i T)) func() {
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
func IfPanics(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
func PrintErrorMessage() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
}
}
82.GO
CURRYING AND COMBINATORS
func main() {
printErrors := IfPanics(PrintErrorMessage)
for _, v := range os.Args[1:] {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
}
}
func ValidInteger[T Integer](v string, f func(i T)) func() {
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
func IfPanics(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
func PrintErrorMessage() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
}
}
82.GO
CURRYING AND COMBINATORS
func main() {
printErrors := IfPanics(PrintErrorMessage)
for _, v := range os.Args[1:] {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
}
}
func ValidInteger[T Integer](v string, f func(i T)) func() {
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
func IfPanics(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
func PrintErrorMessage() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
}
}
82.GO
CURRYING AND COMBINATORS
func main() {
printErrors := IfPanics(PrintErrorMessage)
for _, v := range os.Args[1:] {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
}
}
func ValidInteger[T Integer](v string, f func(i T)) func() {
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
func IfPanics(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
func PrintErrorMessage() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
}
}
82.GO
CURRYING AND COMBINATORS
func main() {
printErrors := IfPanics(PrintErrorMessage)
for _, v := range os.Args[1:] {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
}
}
func ValidInteger[T Integer](v string, f func(i T)) func() {
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(T(x))
} else {
panic(v)
}
}
}
func IfPanics(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
func PrintErrorMessage() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %v", x)
}
}
82.GO
FUNCTIONS
IN
MATHEMATICS
RECURSION
RECURSION
package main
func main() {
main()
}
83.GO
RECURSION
package main
func main() {
main()
}
83.GO
RECURSION
package main
func main() {
main()
}
83.GO
RECURSION
var limit int
func init() {
if x, e := strconv.Atoi(os.Args[1]); e == nil {
limit = x
}
}
func main() {
limit--
if limit > 0 {
main()
}
}
85.GO
RECURSION
var limit int
func init() {
if x, e := strconv.Atoi(os.Args[1]); e == nil {
limit = x
}
}
func main() {
limit--
if limit > 0 {
main()
}
}
85.GO
RECURSION
var limit int
func init() {
if x, e := strconv.Atoi(os.Args[1]); e == nil {
limit = x
}
}
func main() {
limit--
if limit > 0 {
main()
}
}
85.GO
RECURSION
var limit int
func init() {
if x, e := strconv.Atoi(os.Args[1]); e == nil {
limit = x
}
}
func main() {
limit--
if limit > 0 {
main()
}
}
85.GO
RECURSION
RECURSION
RECURSION
RECURSION
func main() {
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
})
}
func Each[T any](s []T, f func(T)) {
if len(s) > 0 {
f(s[0])
Each(s[1:], f)
}
}
func Factorial[T Integer](n T) (r T) {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * Factorial(n-1)
}
return
}
91.GO
RECURSION
func main() {
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
})
}
func Each[T any](s []T, f func(T)) {
if len(s) > 0 {
f(s[0])
Each(s[1:], f)
}
}
func Factorial[T Integer](n T) (r T) {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * Factorial(n-1)
}
return
}
91.GO
RECURSION
func main() {
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
})
}
func Each[T any](s []T, f func(T)) {
if len(s) > 0 {
f(s[0])
Each(s[1:], f)
}
}
func Factorial[T Integer](n T) (r T) {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * Factorial(n-1)
}
return
}
91.GO
RECURSION
func main() {
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
})
}
func Each[T any](s []T, f func(T)) {
if len(s) > 0 {
f(s[0])
Each(s[1:], f)
}
}
func Factorial[T Integer](n T) (r T) {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * Factorial(n-1)
}
return
}
91.GO
RECURSION
func main() {
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, Factorial(i))
}))
})
}
func Each[T any](s []T, f func(T)) {
if len(s) > 0 {
f(s[0])
Each(s[1:], f)
}
}
func Factorial[T Integer](n T) (r T) {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * Factorial(n-1)
}
return
}
91.GO
RECURSION
func main() {
f := MakeFactorial[int]()
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, f(i))
}))
})
}
func MakeFactorial[T Integer]() (f func(T) T) {
c := make(Cache[T])
return func(n T) (r T) {
if r = c[n]; r == 0 {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * f(n-1)
}
c[n] = r
c.Dump()
}
return
}
}
type Cache[T Integer] map[T]T
func (c Cache[T]) Dump() {
for k, v := range c {
fmt.Printf("c[%v] = %v", k, v)
}
}
95.GO
RECURSION
func main() {
f := MakeFactorial[int]()
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, f(i))
}))
})
}
func MakeFactorial[T Integer]() (f func(T) T) {
c := make(Cache[T])
return func(n T) (r T) {
if r = c[n]; r == 0 {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * f(n-1)
}
c[n] = r
c.Dump()
}
return
}
}
type Cache[T Integer] map[T]T
func (c Cache[T]) Dump() {
for k, v := range c {
fmt.Printf("c[%v] = %v", k, v)
}
}
95.GO
RECURSION
func main() {
f := MakeFactorial[int]()
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, f(i))
}))
})
}
func MakeFactorial[T Integer]() (f func(T) T) {
c := make(Cache[T])
return func(n T) (r T) {
if r = c[n]; r == 0 {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * f(n-1)
}
c[n] = r
c.Dump()
}
return
}
}
type Cache[T Integer] map[T]T
func (c Cache[T]) Dump() {
for k, v := range c {
fmt.Printf("c[%v] = %v", k, v)
}
}
95.GO
RECURSION
func main() {
f := MakeFactorial[int]()
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, f(i))
}))
})
}
func MakeFactorial[T Integer]() (f func(T) T) {
c := make(Cache[T])
return func(n T) (r T) {
if r = c[n]; r == 0 {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * f(n-1)
}
c[n] = r
c.Dump()
}
return
}
}
type Cache[T Integer] map[T]T
func (c Cache[T]) Dump() {
for k, v := range c {
fmt.Printf("c[%v] = %v", k, v)
}
}
95.GO
RECURSION
func main() {
f := MakeFactorial[int]()
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, f(i))
}))
})
}
func MakeFactorial[T Integer]() (f func(T) T) {
c := make(Cache[T])
return func(n T) (r T) {
if r = c[n]; r == 0 {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * f(n-1)
}
c[n] = r
c.Dump()
}
return
}
}
type Cache[T Integer] map[T]T
func (c Cache[T]) Dump() {
for k, v := range c {
fmt.Printf("c[%v] = %v", k, v)
}
}
95.GO
RECURSION
func main() {
f := MakeFactorial[int]()
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, f(i))
}))
})
}
func MakeFactorial[T Integer]() (f func(T) T) {
c := make(Cache[T])
return func(n T) (r T) {
if r = c[n]; r == 0 {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * f(n-1)
}
c[n] = r
c.Dump()
}
return
}
}
type Cache[T Integer] map[T]T
func (c Cache[T]) Dump() {
for k, v := range c {
fmt.Printf("c[%v] = %v", k, v)
}
}
95.GO
RECURSION
func main() {
f := MakeFactorial[int]()
printErrors := IfPanics(PrintErrorMessage)
Each(os.Args[1:], func(v string) {
printErrors(
ValidInteger(v, func(i int) {
fmt.Printf("%v!: %v", i, f(i))
}))
})
}
func MakeFactorial[T Integer]() (f func(T) T) {
c := make(Cache[T])
return func(n T) (r T) {
if r = c[n]; r == 0 {
switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * f(n-1)
}
c[n] = r
c.Dump()
}
return
}
}
type Cache[T Integer] map[T]T
func (c Cache[T]) Dump() {
for k, v := range c {
fmt.Printf("c[%v] = %v", k, v)
}
}
95.GO
FUNCTIONS
IN
MATHEMATICS
THE Y COMBINATOR
THE Y COMBINATOR
so given f(x) = x2 - 3x + 4
f(2) = 2 is a fixed point
meaning that calculating f for a value returns that value unchanged
THE Y COMBINATOR
Y g = (λf.(λx.f (x x)) (λx.f (x x))) g
= (λx.g (x x)) (λx.g (x x))
= g ((λx.g (x x)) (λx.g (x x)))
= g (Y g)
in untyped lambda calculus every function has a fixed point
(this is not the general case in mathematics)
this Y combinator creates recursive functions
from anonymous functions (func values in Go)
THE Y COMBINATOR
// Y = ->f.(->x.f(x x))(->x.f(x x))
func Y(g func(any) any) func(any) any {
return func(f any) func(any) any {
return f.(func(any) any)(f).(func(any) any)
}(func(f any) any {
return g(func(x any) any {
return f.(func(any) any)(f).(func(any) any)(x)
})
})
}
func main() {
factorial := Y(func(g any) any {
return func(n any) (r any) {
if n, ok := n.(int); ok {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g.(func(any) any)(n-1).(int)
}
panic(n)
}
})
os.Exit(factorial(5).(int))
}
101.GO
THE Y COMBINATOR
// Y = ->f.(->x.f(x x))(->x.f(x x))
func Y(g func(any) any) func(any) any {
return func(f any) func(any) any {
return f.(func(any) any)(f).(func(any) any)
}(func(f any) any {
return g(func(x any) any {
return f.(func(any) any)(f).(func(any) any)(x)
})
})
}
func main() {
factorial := Y(func(g any) any {
return func(n any) (r any) {
if n, ok := n.(int); ok {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g.(func(any) any)(n-1).(int)
}
panic(n)
}
})
os.Exit(factorial(5).(int))
}
101.GO
THE Y COMBINATOR
// Y = ->f.(->x.f(x x))(->x.f(x x))
func Y(g func(any) any) func(any) any {
return func(f any) func(any) any {
return f.(func(any) any)(f).(func(any) any)
}(func(f any) any {
return g(func(x any) any {
return f.(func(any) any)(f).(func(any) any)(x)
})
})
}
func main() {
factorial := Y(func(g any) any {
return func(n any) (r any) {
if n, ok := n.(int); ok {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g.(func(any) any)(n-1).(int)
}
panic(n)
}
})
os.Exit(factorial(5).(int))
}
101.GO
THE Y COMBINATOR
// Y = ->f.(->x.f(x x))(->x.f(x x))
func Y(g func(any) any) func(any) any {
return func(f any) func(any) any {
return f.(func(any) any)(f).(func(any) any)
}(func(f any) any {
return g(func(x any) any {
return f.(func(any) any)(f).(func(any) any)(x)
})
})
}
func main() {
factorial := Y(func(g any) any {
return func(n any) (r any) {
if n, ok := n.(int); ok {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g.(func(any) any)(n-1).(int)
}
panic(n)
}
})
os.Exit(factorial(5).(int))
}
101.GO
THE Y COMBINATOR
// Y = ->f.(->x.f(x x))(->x.f(x x))
func Y(g func(any) any) func(any) any {
return func(f any) func(any) any {
return f.(func(any) any)(f).(func(any) any)
}(func(f any) any {
return g(func(x any) any {
return f.(func(any) any)(f).(func(any) any)(x)
})
})
}
func main() {
factorial := Y(func(g any) any {
return func(n any) (r any) {
if n, ok := n.(int); ok {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g.(func(any) any)(n-1).(int)
}
panic(n)
}
})
os.Exit(factorial(5).(int))
}
101.GO
THE Y COMBINATOR
type Function func(any) any
func Recurse(f any) Function {
return f.(func(any) any)(f).(func(any) any)
}
func Y(g Function) Function {
return Recurse(
func(f any) any {
return g(func(x any) any {
return Recurse(f)(x)
})
})
}
102.GO
THE Y COMBINATOR
type Function func(any) any
func Recurse(f any) Function {
return f.(func(any) any)(f).(func(any) any)
}
func Y(g Function) Function {
return Recurse(
func(f any) any {
return g(func(x any) any {
return Recurse(f)(x)
})
})
}
102.GO
THE Y COMBINATOR
type Function func(any) any
func Recurse(f any) Function {
return f.(func(any) any)(f).(func(any) any)
}
func Y(g Function) Function {
return Recurse(
func(f any) any {
return g(func(x any) any {
return Recurse(f)(x)
})
})
}
102.GO
THE Y COMBINATOR
Y g = (λf.(λx.f (x x)) (λx.f (x x))) g
= (λx.g (x x)) (λx.g (x x))
= g ((λx.g (x x)) (λx.g (x x)))
= g (Y g)
in untyped lambda calculus every function has a fixed point
(this is not the general case in mathematics)
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
func Recurse(f Function) Function {
return f(f).(Function)
}
func Y(g Transformer) Function {
return Recurse(
func(f any) any {
return g(func(x any) any {
return Recurse(f.(Function))(x)
})
})
}
func main() {
factorial := Y(func(g Function) Function {
return func(n any) any {
if n, ok := n.(int); ok {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1).(int)
}
panic(n)
}
})
os.Exit(factorial(5).(int))
}
103.GO
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
func Recurse(f Function) Function {
return f(f).(Function)
}
func Y(g Transformer) Function {
return Recurse(
func(f any) any {
return g(func(x any) any {
return Recurse(f.(Function))(x)
})
})
}
func main() {
factorial := Y(func(g Function) Function {
return func(n any) any {
if n, ok := n.(int); ok {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1).(int)
}
panic(n)
}
})
os.Exit(factorial(5).(int))
}
103.GO
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
func Recurse(f Function) Function {
return f(f).(Function)
}
func Y(g Transformer) Function {
return Recurse(
func(f any) any {
return g(func(x any) any {
return Recurse(f.(Function))(x)
})
})
}
func main() {
factorial := Y(func(g Function) Function {
return func(n any) any {
if n, ok := n.(int); ok {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1).(int)
}
panic(n)
}
})
os.Exit(factorial(5).(int))
}
103.GO
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
func Recurse(f Function) Function {
return f(f).(Function)
}
func Y(g Transformer) Function {
return Recurse(
func(f any) any {
return g(func(x any) any {
return Recurse(f.(Function))(x)
})
})
}
func main() {
factorial := Y(func(g Function) Function {
return func(n any) any {
if n, ok := n.(int); ok {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1).(int)
}
panic(n)
}
})
os.Exit(factorial(5).(int))
}
103.GO
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
func Recurse(f Function) Function {
return f(f).(Function)
}
func Y(g Transformer) Function {
return Recurse(
func(f any) any {
return g(func(x any) any {
return Recurse(f.(Function))(x)
})
})
}
func main() {
factorial := Y(func(g Function) Function {
return func(n any) any {
if n, ok := n.(int); ok {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1).(int)
}
panic(n)
}
})
os.Exit(factorial(5).(int))
}
103.GO
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
type Recursive func(Recursive) Function
func (r Recursive) Apply(f Transformer) Function {
return f(r(r))
}
func Y(f Transformer) Function {
g := func(r Recursive) Function {
return func(x any) any {
return r.Apply(f)(x)
}
}
return g(g)
}
104.GO
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
type Recursive func(Recursive) Function
func (r Recursive) Apply(f Transformer) Function {
return f(r(r))
}
func Y(f Transformer) Function {
g := func(r Recursive) Function {
return func(x any) any {
return r.Apply(f)(x)
}
}
return g(g)
}
104.GO
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
type Recursive func(Recursive) Function
func (r Recursive) Apply(f Transformer) Function {
return f(r(r))
}
func Y(f Transformer) Function {
g := func(r Recursive) Function {
return func(x any) any {
return r.Apply(f)(x)
}
}
return g(g)
}
104.GO
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
type Recursive func(Recursive) Function
func (r Recursive) Apply(f Transformer) Function {
return f(r(r))
}
func Y(f Transformer) Function {
g := func(r Recursive) Function {
return func(x any) any {
return r.Apply(f)(x)
}
}
return g(g)
}
104.GO
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
type Recursive func(Recursive) Function
func (r Recursive) Apply(f Transformer) Function {
return f(r(r))
}
func Y(f Transformer) Function {
g := func(r Recursive) Function {
return func(x any) any {
return r.Apply(f)(x)
}
}
return g(g)
}
104.GO
THE Y COMBINATOR
type Function func(any) any
type Transformer func(Function) Function
type Recursive func(Recursive) Function
func (r Recursive) Apply(f Transformer) Function {
return f(r(r))
}
func Y(f Transformer) Function {
g := func(r Recursive) Function {
return func(x any) any {
return r.Apply(f)(x)
}
}
return g(g)
}
104.GO
THE Y COMBINATOR
type Function[T any] func(T) T
type Transformer[T any] func(Function[T]) Function[T]
type Recursive[T any] func(Recursive[T]) Function[T]
func (r Recursive[T]) Apply(f Transformer[T]) Function[T] {
return f(r(r))
}
func Y[T any](f Transformer[T]) Function[T] {
g := func(r Recursive[T]) Function[T] {
return func(x T) T {
return r.Apply(f)(x)
}
}
return g(g)
}
func main() {
factorial := Y(func(g Function[int]) Function[int] {
return func(n int) int {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1)
}
})
os.Exit(factorial(5))
}
105.GO
THE Y COMBINATOR
type Function[T any] func(T) T
type Transformer[T any] func(Function[T]) Function[T]
type Recursive[T any] func(Recursive[T]) Function[T]
func (r Recursive[T]) Apply(f Transformer[T]) Function[T] {
return f(r(r))
}
func Y[T any](f Transformer[T]) Function[T] {
g := func(r Recursive[T]) Function[T] {
return func(x T) T {
return r.Apply(f)(x)
}
}
return g(g)
}
func main() {
factorial := Y(func(g Function[int]) Function[int] {
return func(n int) int {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1)
}
})
os.Exit(factorial(5))
}
105.GO
THE Y COMBINATOR
func Y[T comparable](f Transformer[T]) Function[T] {
memo := make(map[T]T)
g := func(r Recursive[T]) Function[T] {
return func(x T) T {
if _, ok := memo[x]; !ok {
memo[x] = r.Apply(f)(x)
fmt.Printf("Y: setting memo[%v] = %v", x, memo[x])
}
return memo[x]
}
}
return g(g)
}
func main() {
factorial := Y(func(g Function[int]) Function[int] {
return func(n int) int {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1)
}
})
fmt.Printf("%v! = %v", 7, factorial(7))
fmt.Printf("%v! = %v", 8, factorial(8))
fmt.Printf("%v! = %v", 5, factorial(5))
}
106.GO
THE Y COMBINATOR
func Y[T comparable](f Transformer[T]) Function[T] {
memo := make(map[T]T)
g := func(r Recursive[T]) Function[T] {
return func(x T) T {
if _, ok := memo[x]; !ok {
memo[x] = r.Apply(f)(x)
fmt.Printf("Y: setting memo[%v] = %v", x, memo[x])
}
return memo[x]
}
}
return g(g)
}
func main() {
factorial := Y(func(g Function[int]) Function[int] {
return func(n int) int {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1)
}
})
fmt.Printf("%v! = %v", 7, factorial(7))
fmt.Printf("%v! = %v", 8, factorial(8))
fmt.Printf("%v! = %v", 5, factorial(5))
}
106.GO
THE Y COMBINATOR
func Y[T comparable](f Transformer[T]) Function[T] {
memo := make(map[T]T)
g := func(r Recursive[T]) Function[T] {
return func(x T) T {
if _, ok := memo[x]; !ok {
memo[x] = r.Apply(f)(x)
fmt.Printf("Y: setting memo[%v] = %v", x, memo[x])
}
return memo[x]
}
}
return g(g)
}
func main() {
factorial := Y(func(g Function[int]) Function[int] {
return func(n int) int {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1)
}
})
fmt.Printf("%v! = %v", 7, factorial(7))
fmt.Printf("%v! = %v", 8, factorial(8))
fmt.Printf("%v! = %v", 5, factorial(5))
}
106.GO
THE Y COMBINATOR
func Y[T comparable](f Transformer[T]) Function[T] {
memo := make(map[T]T)
g := func(r Recursive[T]) Function[T] {
return func(x T) T {
if _, ok := memo[x]; !ok {
memo[x] = r.Apply(f)(x)
fmt.Printf("Y: setting memo[%v] = %v", x, memo[x])
}
return memo[x]
}
}
return g(g)
}
func main() {
factorial := Y(func(g Function[int]) Function[int] {
return func(n int) int {
switch {
case n < 0:
panic(n)
case n < 2:
return 1
}
return n * g(n-1)
}
})
fmt.Printf("%v! = %v", 7, factorial(7))
fmt.Printf("%v! = %v", 8, factorial(8))
fmt.Printf("%v! = %v", 5, factorial(5))
}
106.GO