AN
INTRODUCTION
TO
FUNCTIONAL PROGRAMMING
IN
GO [Y COMBINATOR REMIX]
ELEANOR MCHUGH
ELEANOR MCHUGH
@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
FUNCTIONS
IN
MATHEMATICS
FUNCTIONS
IN
MATHEMATICS
COMPUTING FACTORIALS
COMPUTING FACTORIALS
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
COMPUTING FACTORIALS
FUNCTIONS
IN
MATHEMATICS
ITERATING FACTORIALS
ITERATING FACTORIALS
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
fmt.Printf("%v!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %vn", 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!: %vn", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %vn", 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!: %vn", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %vn", 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!: %vn", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %vn", 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!: %vn", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
fmt.Printf("no defined value for %vn", 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!: %vn", 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 %vn", 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!: %vn", 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 %vn", 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!: %vn", 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 %vn", 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!: %vn", 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 %vn", 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!: %vn", 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 %vn", 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!: %vn", 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 %vn", 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!: %vn", 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 %vn", 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!: %vn", 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 %vn", 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!: %vn", 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 %vn", 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!: %vn", 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 %vn", 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
package main
func main() {
defer func() {
recover()
}
main()
}
84.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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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!: %vn", 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] = %vn", 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!: %vn", 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] = %vn", 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!: %vn", 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] = %vn", 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!: %vn", 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] = %vn", 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!: %vn", 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] = %vn", 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!: %vn", 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] = %vn", 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!: %vn", 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] = %vn", 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
fi
xed 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
fi
xed 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
fi
xed 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] = %vn", 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! = %vn", 7, factorial(7))
fmt.Printf("%v! = %vn", 8, factorial(8))
fmt.Printf("%v! = %vn", 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] = %vn", 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! = %vn", 7, factorial(7))
fmt.Printf("%v! = %vn", 8, factorial(8))
fmt.Printf("%v! = %vn", 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] = %vn", 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! = %vn", 7, factorial(7))
fmt.Printf("%v! = %vn", 8, factorial(8))
fmt.Printf("%v! = %vn", 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] = %vn", 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! = %vn", 7, factorial(7))
fmt.Printf("%v! = %vn", 8, factorial(8))
fmt.Printf("%v! = %vn", 5, factorial(5))
}
106.GO
SHOW
ME
MORE
LEANPUB://GONOTEBOOK SLIDESHARE
GITHUB

[2024] An Introduction to Functional Programming with Go [Y Combinator Remix].pdf

  • 1.
  • 2.
    ELEANOR MCHUGH @feyeleanor MISAPPLIED PHYSICIST EMBEDDEDSYSTEMS VIRTUAL MACHINES P2P NETWORKING DIGITAL IDENTITY SECURE COMMS JAVASCRIPT RUBY GO
  • 3.
    OO makes codeunderstandable 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]
  • 4.
  • 5.
  • 6.
  • 7.
    A PURE FUNCTION packagemain import "os" func main() { os.Exit(add(3, 4)) } func add(x, y int) int { return x + y } 50.GO
  • 8.
    A PURE FUNCTION packagemain import "os" func main() { os.Exit(add(3, 4)) } func add(x, y int) int { return x + y } 50.GO
  • 9.
    A PURE FUNCTION packagemain import "os" func main() { os.Exit(add(3, 4)) } func add(x int, y int) int { return x + y } 50.GO
  • 10.
    A PURE FUNCTION packagemain import "os" func main() { os.Exit(add(3, 4)) } func add(x int, y int) int { return x + y } 50.GO
  • 11.
    A PURE FUNCTION packagemain import "os" func main() { os.Exit(add(3, 4)) } func add(x int, y int) int { return x + y } 50.GO
  • 12.
    A PURE FUNCTION funcmain() { 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
  • 13.
    A PURE FUNCTION funcmain() { 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
  • 14.
    A PURE FUNCTION funcmain() { 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
  • 15.
    A PURE FUNCTION packagemain 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
  • 16.
    A PURE FUNCTION packagemain 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
  • 17.
    A PURE FUNCTION packagemain 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
  • 18.
    A PURE FUNCTION funcmain() { 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
  • 19.
    A PURE FUNCTION funcmain() { 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
  • 20.
    A PURE FUNCTION funcmain() { 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
  • 21.
    A PURE FUNCTION funcmain() { 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
  • 22.
    A PURE FUNCTION funcmain() { 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
  • 23.
    A PURE FUNCTION funcmain() { 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
  • 24.
    A PURE FUNCTION funcmain() { 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
  • 25.
    A PURE FUNCTION funcmain() { 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
  • 26.
  • 27.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 28.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 29.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 30.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 31.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 32.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 33.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 34.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 35.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 36.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 37.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 38.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 39.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 40.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 41.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 42.
    FUNCTIONS WITH SIDE-EFFECTS funcmain() { 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
  • 43.
  • 44.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 45.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 46.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 47.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 48.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 49.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 50.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 51.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 52.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 53.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 54.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 55.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 56.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 57.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 58.
    FUNCTIONS AS OBJECTS funcmain() { 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
  • 59.
  • 60.
  • 61.
  • 62.
    0! = 1 1!= 1 2! = 2 3! = 6 4! = 24 5! = 120 6! = 720 7! = 5040 8! = 40320 9! = 362880 COMPUTING FACTORIALS
  • 63.
  • 64.
    ITERATING FACTORIALS func main(){ defer func() { if x := recover(); x != nil { fmt.Println("no factorial") } }() x, _ := strconv.Atoi(os.Args[1]) fmt.Printf("%v!: %vn", 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
  • 65.
    ITERATING FACTORIALS func main(){ defer func() { if x := recover(); x != nil { fmt.Println("no factorial") } }() x, _ := strconv.Atoi(os.Args[1]) fmt.Printf("%v!: %vn", 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
  • 66.
    ITERATING FACTORIALS func main(){ defer func() { if x := recover(); x != nil { fmt.Println("no factorial") } }() x, _ := strconv.Atoi(os.Args[1]) fmt.Printf("%v!: %vn", 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
  • 67.
    ITERATING FACTORIALS func main(){ defer func() { if x := recover(); x != nil { fmt.Println("no factorial") } }() x, _ := strconv.Atoi(os.Args[1]) fmt.Printf("%v!: %vn", 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
  • 68.
    ITERATING FACTORIALS func main(){ defer func() { if x := recover(); x != nil { fmt.Println("no factorial") } }() x, _ := strconv.Atoi(os.Args[1]) fmt.Printf("%v!: %vn", 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
  • 69.
    ITERATING FACTORIALS func main(){ defer func() { if x := recover(); x != nil { fmt.Println("no factorial") } }() x, _ := strconv.Atoi(os.Args[1]) fmt.Printf("%v!: %vn", 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
  • 70.
    ITERATING FACTORIALS func main(){ defer func() { if x := recover(); x != nil { fmt.Println("no factorial") } }() x, _ := strconv.Atoi(os.Args[1]) fmt.Printf("%v!: %vn", 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
  • 71.
    ITERATING FACTORIALS func main(){ defer func() { if x := recover(); x != nil { fmt.Println("no factorial") } }() x, _ := strconv.Atoi(os.Args[1]) fmt.Printf("%v!: %vn", 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
  • 72.
    ITERATING FACTORIALS func main(){ defer func() { if x := recover(); x != nil { fmt.Println("no factorial") } }() x, _ := strconv.Atoi(os.Args[1]) fmt.Printf("%v!: %vn", 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
  • 73.
    ITERATING FACTORIALS func main(){ defer func() { if x := recover(); x != nil { fmt.Println("no factorial") } }() x, _ := strconv.Atoi(os.Args[1]) fmt.Printf("%v!: %vn", 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
  • 74.
  • 75.
    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!: %vn", 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
  • 76.
    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!: %vn", 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
  • 77.
    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!: %vn", 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
  • 78.
    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!: %vn", 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
  • 79.
    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!: %vn", 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
  • 80.
    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!: %vn", 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
  • 81.
    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!: %vn", 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
  • 82.
    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!: %vn", 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
  • 83.
  • 84.
    HIGHER ORDER FUNCTIONS funcmain() { var errors int computeFactorial := ForValidValues( func(i int) { fmt.Printf("%v!: %vn", i, Factorial(i)) }, func() { if x := recover(); x != nil { fmt.Printf("no defined value for %vn", 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
  • 85.
    HIGHER ORDER FUNCTIONS funcmain() { var errors int computeFactorial := ForValidValues( func(i int) { fmt.Printf("%v!: %vn", i, Factorial(i)) }, func() { if x := recover(); x != nil { fmt.Printf("no defined value for %vn", 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
  • 86.
    HIGHER ORDER FUNCTIONS funcmain() { var errors int computeFactorial := ForValidValues( func(i int) { fmt.Printf("%v!: %vn", i, Factorial(i)) }, func() { if x := recover(); x != nil { fmt.Printf("no defined value for %vn", 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
  • 87.
    HIGHER ORDER FUNCTIONS funcmain() { var errors int computeFactorial := ForValidValues( func(i int) { fmt.Printf("%v!: %vn", i, Factorial(i)) }, func() { if x := recover(); x != nil { fmt.Printf("no defined value for %vn", 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
  • 88.
    HIGHER ORDER FUNCTIONS funcmain() { var errors int computeFactorial := ForValidValues( func(i int) { fmt.Printf("%v!: %vn", i, Factorial(i)) }, func() { if x := recover(); x != nil { fmt.Printf("no defined value for %vn", 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
  • 89.
  • 90.
  • 91.
    CURRYING AND COMBINATORS funcmain() { printErrors := IfPanics(PrintErrorMessage) for _, v := range os.Args[1:] { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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 %vn", x) } } 82.GO
  • 92.
    CURRYING AND COMBINATORS funcmain() { printErrors := IfPanics(PrintErrorMessage) for _, v := range os.Args[1:] { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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 %vn", x) } } 82.GO
  • 93.
    CURRYING AND COMBINATORS funcmain() { printErrors := IfPanics(PrintErrorMessage) for _, v := range os.Args[1:] { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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 %vn", x) } } 82.GO
  • 94.
    CURRYING AND COMBINATORS funcmain() { printErrors := IfPanics(PrintErrorMessage) for _, v := range os.Args[1:] { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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 %vn", x) } } 82.GO
  • 95.
    CURRYING AND COMBINATORS funcmain() { printErrors := IfPanics(PrintErrorMessage) for _, v := range os.Args[1:] { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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 %vn", x) } } 82.GO
  • 96.
    CURRYING AND COMBINATORS funcmain() { printErrors := IfPanics(PrintErrorMessage) for _, v := range os.Args[1:] { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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 %vn", x) } } 82.GO
  • 97.
    CURRYING AND COMBINATORS funcmain() { printErrors := IfPanics(PrintErrorMessage) for _, v := range os.Args[1:] { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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 %vn", x) } } 82.GO
  • 98.
    CURRYING AND COMBINATORS funcmain() { printErrors := IfPanics(PrintErrorMessage) for _, v := range os.Args[1:] { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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 %vn", x) } } 82.GO
  • 99.
    CURRYING AND COMBINATORS funcmain() { printErrors := IfPanics(PrintErrorMessage) for _, v := range os.Args[1:] { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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 %vn", x) } } 82.GO
  • 100.
    CURRYING AND COMBINATORS funcmain() { printErrors := IfPanics(PrintErrorMessage) for _, v := range os.Args[1:] { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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 %vn", x) } } 82.GO
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
    RECURSION package main func main(){ defer func() { recover() } main() } 84.GO
  • 106.
    RECURSION var limit int funcinit() { if x, e := strconv.Atoi(os.Args[1]); e == nil { limit = x } } func main() { limit-- if limit > 0 { main() } } 85.GO
  • 107.
    RECURSION var limit int funcinit() { if x, e := strconv.Atoi(os.Args[1]); e == nil { limit = x } } func main() { limit-- if limit > 0 { main() } } 85.GO
  • 108.
    RECURSION var limit int funcinit() { if x, e := strconv.Atoi(os.Args[1]); e == nil { limit = x } } func main() { limit-- if limit > 0 { main() } } 85.GO
  • 109.
    RECURSION var limit int funcinit() { if x, e := strconv.Atoi(os.Args[1]); e == nil { limit = x } } func main() { limit-- if limit > 0 { main() } } 85.GO
  • 110.
  • 111.
  • 112.
  • 113.
    RECURSION func main() { printErrors:= IfPanics(PrintErrorMessage) Each(os.Args[1:], func(v string) { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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
  • 114.
    RECURSION func main() { printErrors:= IfPanics(PrintErrorMessage) Each(os.Args[1:], func(v string) { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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
  • 115.
    RECURSION func main() { printErrors:= IfPanics(PrintErrorMessage) Each(os.Args[1:], func(v string) { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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
  • 116.
    RECURSION func main() { printErrors:= IfPanics(PrintErrorMessage) Each(os.Args[1:], func(v string) { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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
  • 117.
    RECURSION func main() { printErrors:= IfPanics(PrintErrorMessage) Each(os.Args[1:], func(v string) { printErrors( ValidInteger(v, func(i int) { fmt.Printf("%v!: %vn", 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
  • 118.
    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!: %vn", 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] = %vn", k, v) } } 95.GO
  • 119.
    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!: %vn", 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] = %vn", k, v) } } 95.GO
  • 120.
    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!: %vn", 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] = %vn", k, v) } } 95.GO
  • 121.
    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!: %vn", 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] = %vn", k, v) } } 95.GO
  • 122.
    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!: %vn", 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] = %vn", k, v) } } 95.GO
  • 123.
    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!: %vn", 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] = %vn", k, v) } } 95.GO
  • 124.
    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!: %vn", 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] = %vn", k, v) } } 95.GO
  • 125.
  • 126.
    THE Y COMBINATOR sogiven f(x) = x2 - 3x + 4 f(2) = 2 is a fi xed point meaning that calculating f for a value returns that value unchanged
  • 127.
    THE Y COMBINATOR Yg = (λ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 fi xed point (this is not the general case in mathematics) this Y combinator creates recursive functions from anonymous functions (func values in Go)
  • 128.
    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
  • 129.
    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
  • 130.
    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
  • 131.
    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
  • 132.
    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
  • 133.
    THE Y COMBINATOR typeFunction 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
  • 134.
    THE Y COMBINATOR typeFunction 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
  • 135.
    THE Y COMBINATOR typeFunction 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
  • 136.
    THE Y COMBINATOR Yg = (λ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 fi xed point (this is not the general case in mathematics)
  • 137.
    THE Y COMBINATOR typeFunction 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
  • 138.
    THE Y COMBINATOR typeFunction 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
  • 139.
    THE Y COMBINATOR typeFunction 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
  • 140.
    THE Y COMBINATOR typeFunction 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
  • 141.
    THE Y COMBINATOR typeFunction 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
  • 142.
    THE Y COMBINATOR typeFunction 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
  • 143.
    THE Y COMBINATOR typeFunction 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
  • 144.
    THE Y COMBINATOR typeFunction 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
  • 145.
    THE Y COMBINATOR typeFunction 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
  • 146.
    THE Y COMBINATOR typeFunction 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
  • 147.
    THE Y COMBINATOR typeFunction 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
  • 148.
    THE Y COMBINATOR typeFunction[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
  • 149.
    THE Y COMBINATOR typeFunction[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
  • 150.
    THE Y COMBINATOR funcY[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] = %vn", 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! = %vn", 7, factorial(7)) fmt.Printf("%v! = %vn", 8, factorial(8)) fmt.Printf("%v! = %vn", 5, factorial(5)) } 106.GO
  • 151.
    THE Y COMBINATOR funcY[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] = %vn", 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! = %vn", 7, factorial(7)) fmt.Printf("%v! = %vn", 8, factorial(8)) fmt.Printf("%v! = %vn", 5, factorial(5)) } 106.GO
  • 152.
    THE Y COMBINATOR funcY[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] = %vn", 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! = %vn", 7, factorial(7)) fmt.Printf("%v! = %vn", 8, factorial(8)) fmt.Printf("%v! = %vn", 5, factorial(5)) } 106.GO
  • 153.
    THE Y COMBINATOR funcY[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] = %vn", 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! = %vn", 7, factorial(7)) fmt.Printf("%v! = %vn", 8, factorial(8)) fmt.Printf("%v! = %vn", 5, factorial(5)) } 106.GO
  • 154.
  • 156.