(2019) An Introduction To Functional Programming With Go

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 255

ELEANOR MCHUGH

AN

INTRODUCTION
TO

FUNCTIONAL PROGRAMMING
IN

GO
APPLIED PHYSICIST
MISAPPLIED HACKER
EMBEDDED SYSTEMS
VIRTUAL MACHINES
DIGITAL IDENTITY
RUBY
GO
C
ELEANOR M HUGH
@feyeleanor
LEANPUB://GONOTEBOOK

A GO DEVELOPER'S NOTEBOOK
▸ teaches Go by exploring code

▸ free tutorial on secure networking

▸ opinionated but not prescriptive

▸ based on a decade of experience

▸ buy once & get all future updates

▸ very irregular update cycle

▸ the only book I'll ever write on Go


LEANPUB://GONOTEBOOK
IMPERATIVE
PROGRAMMING
A SIMPLE TASK

0: 0
1: 2
2: 4
3: 6
4: 8
THE CONDITIONAL LOOP

IMPERATIVE
PROGRAMMING
THE CONDITIONAL LOOP

package main
import "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
fmt.Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
fmt.Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
fmt.Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
THE CONDITIONAL LOOP

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i := 0; i < len(s); i++ {
Printf("%v: %v\n", i, s[i])
}
}
AN EXCEPTIONAL LOOP

IMPERATIVE
PROGRAMMING
AN EXCEPTIONAL LOOP

package main
import . "fmt"

func main() {
defer func() {
recover()
}()
s := []int{0, 2, 4, 6, 8}
i := 0
for {
Printf("%v: %v\n", i, s[i])
i++
}
}
AN EXCEPTIONAL LOOP

package main
import . "fmt"

func main() {
defer func() {
recover()
}()
s := []int{0, 2, 4, 6, 8}
i := 0
for {
Printf("%v: %v\n", i, s[i])
i++
}
}
AN EXCEPTIONAL LOOP

package main
import . "fmt"

func main() {
defer func() {
recover()
}()
s := []int{0, 2, 4, 6, 8}
i := 0
for {
Printf("%v: %v\n", i, s[i])
i++
}
}
AN EXCEPTIONAL LOOP

package main
import . "fmt"

func main() {
defer func() {
recover()
}()
s := []int{0, 2, 4, 6, 8}
i := 0
for {
Printf("%v: %v\n", i, s[i])
i++
}
}
AN EXCEPTIONAL LOOP

package main
import . "fmt"

func main() {
defer func() {
recover()
}()
s := []int{0, 2, 4, 6, 8}
i := 0
for {
Printf("%v: %v\n", i, s[i])
i++
}
}
AN EXCEPTIONAL LOOP

package main
import . "fmt"

func main() {
defer func() {
recover()
}()
s := []int{0, 2, 4, 6, 8}
i := 0
for {
Printf("%v: %v\n", i, s[i])
i++
}
}
AN EXCEPTIONAL LOOP

package main
import . "fmt"

func main() {
defer func() {
recover()
}()
s := []int{0, 2, 4, 6, 8}
for i := 0; ; i++ {
Printf("%v: %v\n", i, s[i])
i++
}
}
ENUMERABLE RANGES

IMPERATIVE
PROGRAMMING
ENUMERABLE RANGES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
ENUMERABLE RANGES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
ENUMERABLE RANGES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
ENUMERABLE RANGES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
ENUMERABLE RANGES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
ENUMERABLE RANGES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
PROGRAMMING
WITH

FUNCTIONS
ENUMERATION BY FUNCTION

PROGRAMMING
WITH

FUNCTIONS
ENUMERATION BY FUNCTION

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s []int) {


for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
ENUMERATION BY FUNCTION

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s []int) {


for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
ENUMERATION BY FUNCTION

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s []int) {


for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
ENUMERATION BY FUNCTION

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s []int) {


for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
ENUMERATION BY FUNCTION

package main
import . "fmt"

func main() {
print_slice(0, 2, 4, 6, 8)
}

func print_slice(s ...int) {


for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
TYPE ABSTRACTION

PROGRAMMING
WITH

FUNCTIONS
ABSTRACTING TYPE

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s interface{}) {


for i, v := range s.([]int) {
Printf("%v: %v\n", i, v)
}
}
ABSTRACTING TYPE

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s interface{}) {


for i, v := range s.([]int) {
Printf("%v: %v\n", i, v)
}
}
ABSTRACTING TYPE

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s interface{}) {


for i, v := range s.([]int) {
Printf("%v: %v\n", i, v)
}
}
ABSTRACTING TYPE

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s interface{}) {


if s, ok := s.([]int); ok {
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
ABSTRACTING TYPE

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s interface{}) {


if s, ok := s.([]int); ok {
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
ABSTRACTING TYPE

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s interface{}) {


if s, ok := s.([]int); ok {
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
ABSTRACTING TYPE

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s interface{}) {


if s, ok := s.([]int); ok {
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
ABSTRACTING TYPE

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case []int:
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
ABSTRACTING TYPE

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case []int:
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
ABSTRACTING TYPE

package main
import . "fmt"

func main() {
print_slice([]int{0, 2, 4, 6, 8})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case []int:
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
FUNCTIONS AS VALUES

PROGRAMMING
WITH

FUNCTIONS
FUNCTIONS AS VALUES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(s, element)
}

func element(s []int, i int) int {


return s[i]
}

func print_slice(s []int, f func([]int, int) int {


defer func() {
recover()
}()
for i := 0; ; i++ {
Printf("%v: %v\n", i, f(i))
}
}
FUNCTIONS AS VALUES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(s, element)
}

func element(s []int, i int) int {


return s[i]
}

func print_slice(s []int, f func([]int, int) int {


defer func() {
recover()
}()
for i := 0; ; i++ {
Printf("%v: %v\n", i, f(i))
}
}
FUNCTIONS AS VALUES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(s, element)
}

func element(s []int, i int) int {


return s[i]
}

func print_slice(s []int, f func([]int, int) int) {


defer func() {
recover()
}()
for i := 0; ; i++ {
Printf("%v: %v\n", i, f(s, i))
}
}
FUNCTIONS AS VALUES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(s, element)
}

func element(s []int, i int) int {


return s[i]
}

func print_slice(s []int, f func([]int, int) int) {


defer func() {
recover()
}()
for i := 0; ; i++ {
Printf("%v: %v\n", i, f(s, i))
}
}
FUNCTIONS AS VALUES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(s, element)
}

func element(s []int, i int) int {


return s[i]
}

func print_slice(s []int, f func([]int, int) int) {


defer func() {
recover()
}()
for i := 0; ; i++ {
Printf("%v: %v\n", i, f(s, i))
}
}
FUNCTIONS AS VALUES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(s, element)
}

func element(s []int, i int) int {


return s[i]
}

func print_slice(s []int, f func([]int, int) int) {


defer func() {
recover()
}()
for i := 0; ; i++ {
Printf("%v: %v\n", i, f(s, i))
}
}
FUNCTIONS AS VALUES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(s, func(s []int, i int) int {
return s[i]
})
}

func print_slice(s []int, f func([]int, int) int) {


defer func() {
recover()
}()
for i := 0; ; i++ {
Printf("%v: %v\n", i, f(s, i))
}
}
CLOSURES

PROGRAMMING
WITH

FUNCTIONS
CLOSURES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(func(i int) int {
return s[i]
})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
}
}
CLOSURES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(func(i int) int {
return s[i]
})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
}
}
CLOSURES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(func(i int) int {
return s[i]
})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
}
}
CLOSURES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(func(i int) int {
return s[i]
})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
}
}
CLOSURES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(func(i int) int {
return s[i]
})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
}
}
CLOSURES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(func(i int) int {
return s[i]
})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
}
}
CLOSURES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(func(i int) int {
return s[i]
})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
}
}
CLOSURES

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_slice(func(i int) int {
return s[i]
})
}

func print_slice(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
}
}
CONCURRENCY

PROGRAMMING
WITH

FUNCTIONS
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int)
go func() {
for i := 0; i++; i < 5 {
c <- i * 2
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int)
go func() {
for i := 0; i++; i < 5 {
c <- i * 2
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int, 16)
go func() {
for i := 0; i++; i < 5 {
c <- i * 2
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int)
go func() {
for i := 0; i++; i < 5 {
c <- i * 2
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int)
go func() {
for i := 0; i++; i < 5 {
c <- i * 2
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int)
go func() {
for i := 0; i++; i < 5 {
c <- i * 2
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int)
go func() {
for i := 0; i++; i < 5 {
c <- i * 2
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int)
go func() {
for _, v := range []int{0, 2, 4, 6, 8} {
c <- v
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int)
go func() {
for _, v := range []int{0, 2, 4, 6, 8} {
c <- v
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int)
go func() {
for _, v := range []int{0, 2, 4, 6, 8} {
c <- v
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
CONCURRENCY

package main
import . "fmt"

func main() {
c := make(chan int)
go func() {
for _, v := range []int{0, 2, 4, 6, 8} {
c <- v
}
close(c)
}()
print_channel(c)
}

func print_channel(c chan int) (i int) {


for v := range c {
Printf("%v: %v\n", i, v)
i++
}
return
}
INFINITE SEQUENCES

PROGRAMMING
WITH

FUNCTIONS
INFINITE SEQUENCES

package main
import . "fmt"

func main() {
c := make(chan int)
go sequence(c)
print_channel(c)
}

func sequence(c chan int) {


for i := 0; ; i++ {
c <- i * 2
}
}

func print_channel(c chan int) {


for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, <- c)
}
return
}
INFINITE SEQUENCES

package main
import . "fmt"

func main() {
c := make(chan int)
go sequence(c)
print_channel(c)
}

func sequence(c chan int) {


for i := 0; ; i++ {
c <- i * 2
}
}

func print_channel(c chan int) {


for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, <- c)
}
return
}
INFINITE SEQUENCES

package main
import . "fmt"

func main() {
c := make(chan int)
go sequence(c)
print_channel(c)
}

func sequence(c chan int) {


for i := 0; ; i++ {
c <- i * 2
}
}

func print_channel(c chan int) {


for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, <- c)
}
return
}
INFINITE SEQUENCES

package main
import . "fmt"

func main() {
c := make(chan int)
go sequence(c)
print_channel(c)
}

func sequence(c chan int) {


for i := 0; ; i++ {
c <- i * 2
}
}

func print_channel(c chan int) {


for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, <- c)
}
return
}
INFINITE SEQUENCES

package main
import . "fmt"

func main() {
c := make(chan int)
go sequence(c)
print_channel(c)
}

func sequence(c chan int) {


for i := 0; ; i++ {
c <- i * 2
}
}

func print_channel(c chan int) {


for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, <- c)
}
return
}
WORKING WITH KINDS

PROGRAMMING
WITH

FUNCTIONS
WORKING WITH KINDS

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
case []int:
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
WORKING WITH KINDS

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
case []int:
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
WORKING WITH KINDS

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
case []int:
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
WORKING WITH KINDS

package main
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := s.(type) {
case func(int) int:
for i := 0; i < 5; i++ {
Printf("%v: %v\n", i, s(i))
}
case []int:
for i, v := range s {
Printf("%v: %v\n", i, v)
}
}
}
WORKING WITH KINDS

package main
import "reflect"
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := reflect.ValueOf(s); s.Kind() {
case reflect.Func:
for i := 0; i < 5; i++ {
p := []reflect.Value{ reflect.ValueOf(i) }
Printf("%v: %v\n", i, s.Call(p)[0].Interface())
}
case reflect.Slice:
for i := 0; i < s.Len(); i++ {
Printf("%v: %v\n", i, s.Index(i).Interface())
}
}
}
WORKING WITH KINDS

package main
import "reflect"
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := reflect.ValueOf(s); s.Kind() {
case reflect.Func:
for i := 0; i < 5; i++ {
p := []reflect.Value{ reflect.ValueOf(i) }
Printf("%v: %v\n", i, s.Call(p)[0].Interface())
}
case reflect.Slice:
for i := 0; i < s.Len(); i++ {
Printf("%v: %v\n", i, s.Index(i).Interface())
}
}
}
WORKING WITH KINDS

package main
import "reflect"
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := reflect.ValueOf(s); s.Kind() {
case reflect.Func:
for i := 0; i < 5; i++ {
p := []reflect.Value{ reflect.ValueOf(i) }
Printf("%v: %v\n", i, s.Call(p)[0].Interface())
}
case reflect.Slice:
for i := 0; i < s.Len(); i++ {
Printf("%v: %v\n", i, s.Index(i).Interface())
}
}
}
WORKING WITH KINDS

package main
import "reflect"
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := reflect.ValueOf(s); s.Kind() {
case reflect.Func:
for i := 0; i < 5; i++ {
p := []reflect.Value{ reflect.ValueOf(i) }
Printf("%v: %v\n", i, s.Call(p)[0].Interface())
}
case reflect.Slice:
for i := 0; i < s.Len(); i++ {
Printf("%v: %v\n", i, s.Index(i).Interface())
}
}
}
WORKING WITH KINDS

package main
import . "reflect"
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := ValueOf(s); s.Kind() {
case Func:
for i := 0; i < 5; i++ {
p := []Value{ ValueOf(i) }
Printf("%v: %v\n", i, s.Call(p)[0].Interface())
}
case Slice:
for i := 0; i < s.Len(); i++ {
Printf("%v: %v\n", i, s.Index(i).Interface())
}
}
}
WORKING WITH KINDS

package main
import . "reflect"
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := ValueOf(s); s.Kind() {
case Func:
for i := 0; i < 5; i++ {
p := []Value{ ValueOf(i) }
Printf("%v: %v\n", i, s.Call(p)[0].Interface())
}
case Slice:
for i := 0; i < s.Len(); i++ {
Printf("%v: %v\n", i, s.Index(i).Interface())
}
}
}
WORKING WITH KINDS

package main
import . "reflect"
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := ValueOf(s); s.Kind() {
case Func:
for i := 0; i < 5; i++ {
p := []Value{ ValueOf(i) }
Printf("%v: %v\n", i, s.Call(p)[0].Interface())
}
case Slice:
for i := 0; i < s.Len(); i++ {
Printf("%v: %v\n", i, s.Index(i).Interface())
}
}
}
WORKING WITH KINDS

package main
import . "reflect"
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


defer func() {
recover()
}
switch s := ValueOf(s); s.Kind() {
case Func:
for i := 0; ; i++ {
p := []Value{ ValueOf(i) }
Printf("%v: %v\n", i, s.Call(p)[0].Interface())
}
case Slice:
for i := 0; ; i++ {
Printf("%v: %v\n", i, s.Index(i).Interface())
}
}
}
WORKING WITH KINDS

package main
import . "reflect"
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := ValueOf(s); s.Kind() {
case Func:
for_each(func(i int) {
p := []Value{ ValueOf(i) }
Printf("%v: %v\n", i, s.Call(p)[0].Interface())
})
case Slice:
for_each(func(i int) {
Printf("%v: %v\n", i, s.Index(i).Interface())
})
}
}

func for_each(f func(int)) (i int) {


defer func() {
recover()
}
for ; ; i++ {
f(i)
}
}
WORKING WITH KINDS

package main
import . "reflect"
import . "fmt"

func main() {
s := []int{0, 2, 4, 6, 8}
print_values(s)
print_values(func(i int) int {
return s[i]
})
}

func print_values(s interface{}) {


switch s := ValueOf(s); s.Kind() {
case Func:
p := make([]Value, 1)
for_each(func(i int) {
p[0] = ValueOf(i)
Printf("%v: %v\n", i, s.Call(p)[0].Interface())
})
case Slice:
for_each(func(i int) {
Printf("%v: %v\n", i, s.Index(i).Interface())
})
}
}

func for_each(f func(int)) (i int) {


defer func() {
recover()
}
for ; ; i++ {
f(i)
}
}
PROGRAMMING
WITH

OBJECTS
TYPES + METHODS = OBJECTS

PROGRAMMING
WITH

OBJECTS
TYPES + METHODS = OBJECTS

package main
import . "fmt"

func main() {
s := IterableSlice{ 0, 2, 4, 6, 8 }
i := 0
s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
}

type IterableSlice []int

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
TYPES + METHODS = OBJECTS

package main
import . "fmt"

func main() {
s := IterableSlice{ 0, 2, 4, 6, 8 }
i := 0
s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
}

type IterableSlice []int

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
TYPES + METHODS = OBJECTS

package main
import . "fmt"

func main() {
s := IterableSlice{ 0, 2, 4, 6, 8 }
i := 0
s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
}

type IterableSlice []int

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
TYPES + METHODS = OBJECTS

package main
import . "fmt"

func main() {
s := IterableSlice{ 0, 2, 4, 6, 8 }
i := 0
s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
}

type IterableSlice []int

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
TYPES + METHODS = OBJECTS

package main
import . "fmt"

func main() {
s := IterableSlice{ 0, 2, 4, 6, 8 }
i := 0
s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
}

type IterableSlice []int

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
INTERFACES = POLYMORPHISM

PROGRAMMING
WITH

OBJECTS
INTERFACES = POLYMORPHISM

package main
import . "fmt"

func main() {
var s Iterable = IterableSlice{ 0, 2, 4, 6, 8 }
i := 0
s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
}

type Iterable interface {


Each(func(interface{}))
}

type IterableSlice []int

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
INTERFACES = POLYMORPHISM

package main
import . "fmt"

func main() {
var s Iterable = IterableSlice{ 0, 2, 4, 6, 8 }
i := 0
s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
}

type Iterable interface {


Each(func(interface{}))
}

type IterableSlice []int

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
INTERFACES = POLYMORPHISM

package main
import . "fmt"

func main() {
var s Iterable = IterableSlice{ 0, 2, 4, 6, 8 }
i := 0
s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
}

type Iterable interface {


Each(func(interface{}))
}

type IterableSlice []int

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
INTERFACES = POLYMORPHISM

package main
import . "fmt"

func main() {
print_values(IterableLimit(5))
print_values(IterableSlice{ 0, 2, 4, 6, 8 })
}

func print_values(s Iterable) (i int) {


s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
return i
}

type Iterable interface {


Each(func(interface{}))
}

type IterableLimit int


type IterableSlice []int

func (i IterableLimit) Each(f func(interface{})) {


for v := IterableLimit(0); v < i; v++ {
f(v)
}
}

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
INTERFACES = POLYMORPHISM

package main
import . "fmt"

func main() {
print_values(IterableLimit(5))
print_values(IterableSlice{ 0, 2, 4, 6, 8 })
}

func print_values(s Iterable) (i int) {


s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
return i
}

type Iterable interface {


Each(func(interface{}))
}

type IterableLimit int


type IterableSlice []int

func (i IterableLimit) Each(f func(interface{})) {


for v := IterableLimit(0); v < i; v++ {
f(v)
}
}

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
INTERFACES = POLYMORPHISM

package main
import . "fmt"

func main() {
print_values(IterableLimit(5))
print_values(IterableSlice{ 0, 2, 4, 6, 8 })
}

func print_values(s Iterable) (i int) {


s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
return i
}

type Iterable interface {


Each(func(interface{}))
}

type IterableLimit int


type IterableSlice []int

func (i IterableLimit) Each(f func(interface{})) {


for v := IterableLimit(0); v < i; v++ {
f(v)
}
}

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
INTERFACES = POLYMORPHISM

package main
import . "fmt"

func main() {
print_values(IterableLimit(5))
print_values(IterableSlice{ 0, 2, 4, 6, 8 })
}

func print_values(s Iterable) (i int) {


s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
return i
}

type Iterable interface {


Each(func(interface{}))
}

type IterableLimit int


type IterableSlice []int

func (i IterableLimit) Each(f func(interface{})) {


for v := IterableLimit(0); v < i; v++ {
f(v)
}
}

func (i IterableSlice) Each(f func(interface{})) {


for _, v := range i {
f(v)
}
}
IMMUTABILITY IS A CHOICE

PROGRAMMING
WITH

OBJECTS
IMMUTABILITY IS A CHOICE

package main
import . "fmt"

func main() {
s := IterableRange{ 0, 2, 5 }
print_values(s)
print_values(s)
}

func print_values(s Iterable) (i int) {


s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
return i
}

type Iterable interface {


Each(func(interface{}))
}

type IterableRange struct {


start int
step int
limit int
}

func (r IterableRange) Each(f func(interface{})) {


for; r.limit > 0; r.limit-- {
f(r.start)
r.start += r.step
}
}
IMMUTABILITY IS A CHOICE

package main
import . "fmt"

func main() {
s := IterableRange{ 0, 2, 5 }
print_values(s)
print_values(s)
}

func print_values(s Iterable) (i int) {


s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
return i
}

type Iterable interface {


Each(func(interface{}))
}

type IterableRange struct {


start int
step int
limit int
}

func (r IterableRange) Each(f func(interface{})) {


for; r.limit > 0; r.limit-- {
f(r.start)
r.start += r.step
}
}
IMMUTABILITY IS A CHOICE

package main
import . "fmt"

func main() {
s := IterableRange{ 0, 2, 5 }
print_values(s)
print_values(s)
}

func print_values(s Iterable) (i int) {


s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
return i
}

type Iterable interface {


Each(func(interface{}))
}

type IterableRange struct {


start int
step int
limit int
}

func (r IterableRange) Each(f func(interface{})) {


for; r.limit > 0; r.limit-- {
f(r.start)
r.start += r.step
}
}
IMMUTABILITY IS A CHOICE

package main
import . "fmt"

func main() {
s := IterableRange{ 0, 2, 5 }
print_values(s)
print_values(s)
}

func print_values(s Iterable) (i int) {


s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
return i
}

type Iterable interface {


Each(func(interface{}))
}

type IterableRange struct {


start int
step int
limit int
}

func (r IterableRange) Each(f func(interface{})) {


for; r.limit > 0; r.limit-- {
f(r.start)
r.start += r.step
}
}
IMMUTABILITY IS A CHOICE

package main
import . "fmt"

func main() {
s := &IterableRange{ 0, 2, 5 }
print_values(s)
print_values(s)
}

func print_values(s Iterable) (i int) {


s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
return i
}

type Iterable interface {


Each(func(interface{}))
}

type IterableRange struct {


start int
step int
limit int
}

func (r IterableRange) Each(f func(interface{})) {


for; r.limit > 0; r.limit-- {
f(r.start)
r.start += r.step
}
}
IMMUTABILITY IS A CHOICE

package main
import . "fmt"

func main() {
s := &IterableRange{ 0, 2, 5 }
print_values(s)
print_values(s)
}

func print_values(s Iterable) (i int) {


s.Each(func(v interface{}) {
Printf("%v: %v\n", i, v)
i++
})
return i
}

type Iterable interface {


Each(func(interface{}))
}

type IterableRange struct {


start int
step int
limit int
}

func (r *IterableRange) Each(f func(interface{})) {


for; r.limit > 0; r.limit-- {
f(r.start)
r.start += r.step
}
}
LEANPUB://GONOTEBOOK

OO makes code understandable by


encapsulating moving parts.
FP makes code understandable by
minimizing moving parts.
Michael Feathers
@mfeathers
FUNCTIONS
AS

PARADIGM
A PURE FUNCTION

FUNCTIONS
AS

PARADIGM
A PURE FUNCTION

package main
import "os"

func main() {
os.Exit(add(3, 4))
}

func add(x, y int) int {


return x + y
}
A PURE FUNCTION

package main
import "os"

func main() {
os.Exit(add(3, 4))
}

func add(x, y int) int {


return x + y
}
A PURE FUNCTION

package main
import "os"

func main() {
os.Exit(add(3, 4))
}

func add(x int, y int) int {


return x + y
}
A PURE FUNCTION

package main
import "os"

func main() {
os.Exit(add(3, 4))
}

func add(x int, y int) int {


return x + y
}
A PURE FUNCTION

package main
import "os"

func main() {
os.Exit(add(3, 4))
}

func add(x int, y int) int {


return x + y
}
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))
}

func add(x, y int) int {


return x + y
}
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))
}

func add(x, y int) int {


return x + y
}
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))
}

func add(x, y int) int {


return x + y
}
A PURE FUNCTION

package main
import "os"
import "strconv"

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(x, y int) int {


return x + y
}
A PURE FUNCTION

package main
import "os"
import "strconv"

func main() {
var sum int
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
sum = add(sum, x)
}
os.Exit(sum)
}

func add(x, y int) int {


return x + y
}
A PURE FUNCTION

package main
import "os"
import "strconv"

func main() {
var sum int
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
sum = add(sum, x)
}
os.Exit(sum)
}

func add(x, y int) int {


return x + y
}
BEING IMPURE

FUNCTIONS
AS

PARADIGM
BEING IMPURE

package main
import "os"
import "strconv"

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
}
BEING IMPURE

package main
import "os"
import "strconv"

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
}
BEING IMPURE

package main
import "os"
import "strconv"

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
}
BEING IMPURE

package main
import "os"
import "strconv"

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
}
BEING IMPURE

package main
import "os"
import "strconv"

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)
}
BEING IMPURE

package main
import "os"
import "strconv"

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)
}
BEING IMPURE

package main
import "os"
import "strconv"

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)
}
BEING IMPURE

package main
import "os"
import "strconv"

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)
}
FUNCTIONS WITH MEMORY

FUNCTIONS
AS

PARADIGM
FUNCTIONS WITH MEMORY

package main
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}

var a = MakeAccumulator()

func MakeAccumulator() func(int) int {


var y int
return func(x int) int {
y += x
return y
}
}
FUNCTIONS WITH MEMORY

package main
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}

var a = MakeAccumulator()

func MakeAccumulator() func(int) int {


var y int
return func(x int) int {
y += x
return y
}
}
FUNCTIONS WITH MEMORY

package main
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}

var a = MakeAccumulator()

func MakeAccumulator() func(int) int {


var y int
return func(x int) int {
y += x
return y
}
}
FUNCTIONS WITH MEMORY

package main
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}

var a = MakeAccumulator()

func MakeAccumulator() func(int) int {


var y int
return func(x int) int {
y += x
return y
}
}
FUNCTIONS WITH MEMORY

package main
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}

var a = MakeAccumulator()

func MakeAccumulator() func(int) int {


var y int
return func(x int) int {
y += x
return y
}
}
FUNCTIONS WITH MEMORY

package main
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}

var a = MakeAccumulator()

type Accumulator func(int) int

func MakeAccumulator() Accumulator {


var y int
return func(x int) int {
y += x
return y
}
}
FUNCTIONS WITH MEMORY

package main
import "os"
import "strconv"

func main() {
a := MakeAccumulator()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}

type Accumulator func(int) int

func MakeAccumulator() Accumulator {


var y int
return func(x int) int {
y += x
return y
}
}
FUNCTIONS WITH MEMORY

package main
import "os"
import "strconv"

func main() {
a := MakeAccumulator()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a(0))
}

func MakeAccumulator() func(int) int {


var y int
return func(x int) int {
y += x
return y
}
}
FUNCTIONS AS OBJECTS

FUNCTIONS
AS

PARADIGM
FUNCTIONS AS OBJECTS

package main
import "os"
import "strconv"

func main() {
a := MakeAccumulator()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a.Int())
}

type Accumulator func(int) int

func MakeAccumulator() Accumulator {


var y int
return func(x int) int {
y += x
return y
}
}

func (a Accumulator) Int() int {


return a(0)
}
FUNCTIONS AS OBJECTS

package main
import "os"
import "strconv"

func main() {
a := MakeAccumulator()
for _, v := range os.Args[1:] {
x, _ := strconv.Atoi(v)
a(x)
}
os.Exit(a.Int())
}

type Accumulator func(int) int

func MakeAccumulator() Accumulator {


var y int
return func(x int) int {
y += x
return y
}
}

func (a Accumulator) Int() int {


return a(0)
}
FUNCTIONS AS OBJECTS

package main func (a Accumulator) Int() int {


import "os" return a(0)
import "strconv" }

func main() { func (a Accumulator) Add(x


a := MakeAccumulator() interface{}) {
for _, v := range os.Args[1:] { switch x := x.(type) {
x, _ := strconv.Atoi(v) case int:
a.Add(x) a(x)
} case Accumulator:
os.Exit(a.Int()) a(x.Value())
} }
}
type Accumulator func(int) int

func MakeAccumulator() Accumulator {


var y int
return func(x int) int {
y += x
return y
}
}
FUNCTIONS AS OBJECTS

package main func (a Accumulator) Int() int {


import "os" return a(0)
import "strconv" }

func main() { func (a Accumulator) Add(x


a := MakeAccumulator() interface{}) {
for _, v := range os.Args[1:] { switch x := x.(type) {
x, _ := strconv.Atoi(v) case int:
a.Add(MakeAccumulator()(x)) a(x)
} case Accumulator:
os.Exit(a.Int()) a(x.Value())
} }
}
type Accumulator func(int) int

func MakeAccumulator() Accumulator {


var y int
return func(x int) int {
y += x
return y
}
}
FUNCTIONS AS OBJECTS

package main func (a Accumulator) Int() int {


import "os" return a(0)
import "strconv" }

func main() { func (a Accumulator) Add(x interface{}) {


a := MakeAccumulator() switch x := x.(type) {
for _, v := range os.Args[1:] { case int:
x, _ := strconv.Atoi(v) a(x)
a.Add(MakeAccumulator()(x)) case Integer:
} a(x.Int())
os.Exit(a.Int()) }
} }

type Accumulator func(int) int


type Integer interface {
Int() int
}

func MakeAccumulator() Accumulator {


var y int
return func(x int) int {
y += x
return y
}
}
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
ITERATING FACTORIALS

FUNCTIONS
IN

MATHEMATICS
ITERATING FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = 1
for ; n > 0; n-- {
r *= n
}
}
return
}
ITERATING FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = 1
for ; n > 0; n-- {
r *= n
}
}
return
}
ITERATING FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = 1
for ; n > 0; n-- {
r *= n
}
}
return
}
ITERATING FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = 1
for ; n > 0; n-- {
r *= n
}
}
return
}
ITERATING FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = 1
for ; n > 0; n-- {
r *= n
}
}
return
}
ITERATING FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = 1
for ; n > 0; n-- {
r *= n
}
}
return
}
ITERATING FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) int {


r := 1
switch {
case n < 0:
panic(n)
case n > 0:
for ; n > 0; n-- {
r *= n
}
}
return r
}
ITERATING FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
ITERATING FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
MULTIPLE FACTORIALS

FUNCTIONS
IN

MATHEMATICS
MULTIPLE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e != nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
MULTIPLE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e != nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
MULTIPLE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
MULTIPLE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
MULTIPLE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
MULTIPLE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
MULTIPLE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
HIGHER ORDER FUNCTIONS

FUNCTIONS
IN

MATHEMATICS
HIGHER ORDER FUNCTIONS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
func() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()

if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}()
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
HIGHER ORDER FUNCTIONS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
func() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()

if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}()
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
HIGHER ORDER FUNCTIONS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
func() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()

if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}()
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
HIGHER ORDER FUNCTIONS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
for _, v := range os.Args[1:] {
func() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()

if x, e := strconv.Atoi(v); e == nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}()
}
}

func Factorial(n int) (r int) {


if n < 0 {
panic(n)
}
for r = 1; n > 0; n-- {
r *= n
}
return
}
HIGHER ORDER FUNCTIONS

package main func Factorial(n int) (r int) {


import . "fmt" if n < 0 {
import "os" panic(n)
import "strconv" }
for r = 1; n > 0; n-- {
func main() { r *= n
for _, v := range os.Args[1:] { }
SafeExecute(func(i int) { return
Printf("%v!: %v\n", i, Factorial(i)) }
})(v)
}
}

func SafeExecute(f func(int)) func(string) {


return func(v string) {
defer func() {
if x := recover(); x != nil {
Printf("no defined value for %v\n", x)
}
}()

if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}
HIGHER ORDER FUNCTIONS

package main func Factorial(n int) (r int) {


import . "fmt" if n < 0 {
import "os" panic(n)
import "strconv" }
for r = 1; n > 0; n-- {
func main() { r *= n
for _, v := range os.Args[1:] { }
SafeExecute(func(i int) { return
Printf("%v!: %v\n", i, Factorial(i)) }
})(v)
}
}

func SafeExecute(f func(int)) func(string) {


return func(v string) {
defer func() {
if x := recover(); x != nil {
Printf("no defined value for %v\n", x)
}
}()

if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}
HIGHER ORDER FUNCTIONS

package main func Factorial(n int) (r int) {


import . "fmt" if n < 0 {
import "os" panic(n)
import "strconv" }
for r = 1; n > 0; n-- {
func main() { r *= n
for _, v := range os.Args[1:] { }
SafeExecute(func(i int) { return
Printf("%v!: %v\n", i, Factorial(i)) }
})(v)
}
}

func SafeExecute(f func(int)) func(string) {


return func(v string) {
defer func() {
if x := recover(); x != nil {
Printf("no defined value for %v\n", x)
}
}()

if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}
HIGHER ORDER FUNCTIONS

package main func Factorial(n int) (r int) {


import . "fmt" if n < 0 {
import "os" panic(n)
import "strconv" }
for r = 1; n > 0; n-- {
func main() { r *= n
for _, v := range os.Args[1:] { }
SafeExecute(func(i int) { return
Printf("%v!: %v\n", i, Factorial(i)) }
})(v)
}
}

func SafeExecute(f func(int)) func(string) {


return func(v string) {
defer func() {
if x := recover(); x != nil {
Printf("no defined value for %v\n", x)
}
}()

if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}
HIGHER ORDER FUNCTIONS

package main func Factorial(n int) (r int) {


import . "fmt" if n < 0 {
import "os" panic(n)
import "strconv" }
for r = 1; n > 0; n-- {
func main() { r *= n
var errors int }
f := func(i int) { return
Printf("%v!: %v\n", i, Factorial(i)) }
}
for _, v := range os.Args[1:] {
if !SafeExecute(f)(v) {
errors++
}
}
os.Exit(errors)
}

func SafeExecute(f func(int)) func(string) bool {


return func(v string) (r bool) {
defer func() {
if x := recover(); x != nil {
Printf("no defined value for %v\n", x)
}
}()

if x, e := strconv.Atoi(v); e == nil {
f(x)
r = true
} else {
panic(v)
}
return
}
}
HIGHER ORDER FUNCTIONS

package main func Factorial(n int) (r int) {


import . "fmt" if n < 0 {
import "os" panic(n)
import "strconv" }
for r = 1; n > 0; n-- {
func main() { r *= n
var errors int }
f := func(i int) { return
Printf("%v!: %v\n", i, Factorial(i)) }
}
for _, v := range os.Args[1:] {
if !SafeExecute(f)(v) {
errors++
}
}
os.Exit(errors)
}

func SafeExecute(f func(int)) func(string) bool {


return func(v string) (r bool) {
defer func() {
if x := recover(); x != nil {
Printf("no defined value for %v\n", x)
}
}()

if x, e := strconv.Atoi(v); e == nil {
f(x)
r = true
} else {
panic(v)
}
return
}
}
HIGHER ORDER FUNCTIONS

package main func Factorial(n int) (r int) {


import . "fmt" if n < 0 {
import "os" panic(n)
import "strconv" }
for r = 1; n > 0; n-- {
func main() { r *= n
var errors int }
f := func(i int) { return
Printf("%v!: %v\n", i, Factorial(i)) }
}
for _, v := range os.Args[1:] {
if !SafeExecute(f)(v) {
errors++
}
}
os.Exit(errors)
}

func SafeExecute(f func(int)) func(string) bool {


return func(v string) (r bool) {
defer func() {
if x := recover(); x != nil {
Printf("no defined value for %v\n", x)
}
}()

if x, e := strconv.Atoi(v); e == nil {
f(x)
r = true
} else {
panic(v)
}
return
}
}
HIGHER ORDER FUNCTIONS

package main func Factorial(n int) (r int) {


import . "fmt" if n < 0 {
import "os" panic(n)
import "strconv" }
for r = 1; n > 0; n-- {
func main() { r *= n
var errors int }
f := func(i int) { return
Printf("%v!: %v\n", i, Factorial(i)) }
}
for _, v := range os.Args[1:] {
if !SafeExecute(f)(v) {
errors++
}
}
os.Exit(errors)
}

func SafeExecute(f func(int)) func(string) bool {


return func(v string) (r bool) {
defer func() {
if x := recover(); x != nil {
Printf("no defined value for %v\n", x)
}
}()

if x, e := strconv.Atoi(v); e == nil {
f(x)
r = true
} else {
panic(v)
}
return
}
}
HIGHER ORDER FUNCTIONS

package main func Factorial(n int) (r int) {


import . "fmt" if n < 0 {
import "os" panic(n)
import "strconv" }
for r = 1; n > 0; n-- {
func main() { r *= n
var errors int }
for _, v := range os.Args[1:] { return
SafeExecute( }
func(i int) {
Printf("%v!: %v\n", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
Printf("no defined value for %v\n", x)
errors++
}
},
)(v)
}
os.Exit(errors)
}

func SafeExecute(f func(int), e func()) func(string) {


return func(v string) {
defer e()

if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}
HIGHER ORDER FUNCTIONS

package main func Factorial(n int) (r int) {


import . "fmt" if n < 0 {
import "os" panic(n)
import "strconv" }
for r = 1; n > 0; n-- {
func main() { r *= n
var errors int }
for _, v := range os.Args[1:] { return
SafeExecute( }
func(i int) {
Printf("%v!: %v\n", i, Factorial(i))
},
func() {
if x := recover(); x != nil {
Printf("no defined value for %v\n", x)
errors++
}
},
)(v)
}
os.Exit(errors)
}

func SafeExecute(f func(int), e func()) func(string) {


return func(v string) {
defer e()

if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}
CURRYING

FUNCTIONS
IN

MATHEMATICS
CURRYING
CURRYING

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
for _, v := range os.Args[1:] { func Factorial(n int) (r int) {
OnPanicFor(UseNumericParam(v, func(i int) { if n < 0 {
Printf("%v!: %v\n", i, Factorial(i)) panic(n)
}), PrintErrorMessage) }
} for r = 1; n > 0; n-- {
} r *= n
}
func UseNumericParam(v string, f func(i int)) func() { return
return func() { }
if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}

func OnPanicFor(f, e func()) {


defer e()
f()
}
CURRYING

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
for _, v := range os.Args[1:] { func Factorial(n int) (r int) {
OnPanicFor(UseNumericParam(v, func(i int) { if n < 0 {
Printf("%v!: %v\n", i, Factorial(i)) panic(n)
}), PrintErrorMessage) }
} for r = 1; n > 0; n-- {
} r *= n
}
func UseNumericParam(v string, f func(i int)) func() { return
return func() { }
if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}

func OnPanicFor(f, e func()) {


defer e()
f()
}
CURRYING

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
for _, v := range os.Args[1:] { func Factorial(n int) (r int) {
OnPanicFor(UseNumericParam(v, func(i int) { if n < 0 {
Printf("%v!: %v\n", i, Factorial(i)) panic(n)
}), PrintErrorMessage) }
} for r = 1; n > 0; n-- {
} r *= n
}
func UseNumericParam(v string, f func(i int)) func() { return
return func() { }
if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}

func OnPanicFor(f, e func()) {


defer e()
f()
}
CURRYING

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
for _, v := range os.Args[1:] { func Factorial(n int) (r int) {
OnPanicFor(UseNumericParam(v, func(i int) { if n < 0 {
Printf("%v!: %v\n", i, Factorial(i)) panic(n)
}), PrintErrorMessage) }
} for r = 1; n > 0; n-- {
} r *= n
}
func UseNumericParam(v string, f func(i int)) func() { return
return func() { }
if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}

func OnPanicFor(f, e func()) {


defer e()
f()
}
CURRYING

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
for _, v := range os.Args[1:] { func Factorial(n int) (r int) {
OnPanicFor(UseNumericParam(v, func(i int) { if n < 0 {
Printf("%v!: %v\n", i, Factorial(i)) panic(n)
}), PrintErrorMessage)() }
} for r = 1; n > 0; n-- {
} r *= n
}
func UseNumericParam(v string, f func(i int)) func() { return
return func() { }
if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}

func OnPanicFor(f, e func()) func() {


return func() {
defer e()
f()
}
}
CURRYING

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
for _, v := range os.Args[1:] { func Factorial(n int) (r int) {
OnPanicFor(UseNumericParam(v, func(i int) { if n < 0 {
Printf("%v!: %v\n", i, Factorial(i)) panic(n)
}), PrintErrorMessage)() }
} for r = 1; n > 0; n-- {
} r *= n
}
func UseNumericParam(v string, f func(i int)) func() { return
return func() { }
if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}

func OnPanicFor(f, e func()) func() {


return func() {
defer e()
f()
}
CURRYING

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
for _, v := range os.Args[1:] { func Factorial(n int) (r int) {
OnPanic(PrintErrorMessage)( if n < 0 {
UseNumericParam(v, func(i int) { panic(n)
Printf("%v!: %v\n", i, Factorial(i)) }
})) for r = 1; n > 0; n-- {
} r *= n
} }
return
func UseNumericParam(v string, f func(i int)) func() { }
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}

func OnPanic(e func()) func(func()) {


return func(f func()) {
defer e()
f()
}
}
CURRYING

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
for _, v := range os.Args[1:] { func Factorial(n int) (r int) {
OnPanic(PrintErrorMessage)( if n < 0 {
UseNumericParam(v, func(i int) { panic(n)
Printf("%v!: %v\n", i, Factorial(i)) }
})) for r = 1; n > 0; n-- {
} r *= n
} }
return
func UseNumericParam(v string, f func(i int)) func() { }
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}

func OnPanic(e func()) func(func()) {


return func(f func()) {
defer e()
f()
}
}
CURRYING

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
for _, v := range os.Args[1:] { func Factorial(n int) (r int) {
OnPanic(PrintErrorMessage)( if n < 0 {
UseNumericParam(v, func(i int) { panic(n)
Printf("%v!: %v\n", i, Factorial(i)) }
})) for r = 1; n > 0; n-- {
} r *= n
} }
return
func UseNumericParam(v string, f func(i int)) func() { }
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}

func OnPanic(e func()) func(func()) {


return func(f func()) {
defer e()
f()
}
}
CURRYING

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
p := OnPanic(PrintErrorMessage) func Factorial(n int) (r int) {
for _, v := range os.Args[1:] { if n < 0 {
p(UseNumericParam(v, func(i int) { panic(n)
Printf("%v!: %v\n", i, Factorial(i)) }
})) for r = 1; n > 0; n-- {
} r *= n
} }
return
func UseNumericParam(v string, f func(i int)) func() { }
return func() {
if x, e := strconv.Atoi(v); e == nil {
f(x)
} else {
panic(v)
}
}
}

func OnPanic(e func()) func(func()) {


return func(f func()) {
defer e()
f()
}
}
RECURSION

FUNCTIONS
IN

MATHEMATICS
RECURSION

package main

func main() {
main()
}
RECURSION

package main

func main() {
main()
}
RECURSION

package main

func main() {
main()
}
RECURSION

package main

func main() {
defer func() {
recover()
}
main()
}
RECURSION

package main

import "os"
import"strconv"

var limit int

func init() {
if x, e := strconv.Atoi(os.Args[1]); e == nil {
limit = x
}
}

func main() {
limit--
if limit > 0 {
main()
}
}
RECURSION

package main

import "os"
import"strconv"

var limit int

func init() {
if x, e := strconv.Atoi(os.Args[1]); e == nil {
limit = x
}
}

func main() {
limit--
if limit > 0 {
main()
}
}
RECURSION

package main

import "os"
import"strconv"

var limit int

func init() {
if x, e := strconv.Atoi(os.Args[1]); e == nil {
limit = x
}
}

func main() {
limit--
if limit > 0 {
main()
}
}
RECURSION

package main

import "os"
import"strconv"

var limit int

func init() {
if x, e := strconv.Atoi(os.Args[1]); e == nil {
limit = x
}
}

func main() {
limit--
if limit > 0 {
main()
}
}
RECURSIVE FACTORIALS

FUNCTIONS
IN

MATHEMATICS
RECURSIVE FACTORIALS
RECURSIVE FACTORIALS
RECURSIVE FACTORIALS
RECURSIVE FACTORIALS
RECURSIVE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = 1
for ; n > 0; n-- {
r *= n
}
}
return
}
RECURSIVE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = 1
for ; n > 0; n-- {
r *= n
}
}
return
}
RECURSIVE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = 1
for ; n > 0; n-- {
r *= n
}
}
return
}
RECURSIVE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
x, _ := strconv.Atoi(os.Args[1])
Printf("%v!: %v\n", x, Factorial(x))
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * Factorial(n - 1)
}
return
}
RECURSIVE FACTORIALS

package main
import . "fmt"
import "os"
import "strconv"

func main() {
defer func() {
if x := recover(); x != nil {
Println("no factorial")
}
}()
for _, v := range os.Args[1:] {
if x, e := strconv.Atoi(v); e != nil {
Printf("%v!: %v\n", x, Factorial(x))
} else {
panic(v)
}
}
}

func Factorial(n int) (r int) {


switch {
case n < 0:
panic(n)
case n == 0:
r = 1
default:
r = n * Factorial(n - 1)
}
return
}
RECURSIVE FACTORIALS

package main func PrintErrorMessage() {


import . "fmt" if x := recover(); x != nil {
import "os" Printf("no defined value for %v\n", x)
import "strconv" }
}
func main() {
for _, v := range os.Args[1:] { func Factorial(n int) (r int) {
OnPanic(PrintErrorMessage)( switch {
UseNumericParam(v, func(i int) { case n < 0:
Printf("%v!: %v\n", i, Factorial(i)) panic(n)
})) case n == 0:
} r = 1
} default:
r = n * Factorial(n - 1)
func UseNumericParam(v string, f func(i int)) func() { }
return func() { return
if x, e := strconv.Atoi(v); e == nil { }
f(x)
} else {
panic(v)
}
}
}

func OnPanic(e func()) func(func()) {


return func(f func()) {
defer e()
f()
}
}
RECURSIVE FACTORIALS

package main func Each(s []string, f func(string)) {


import . "fmt" for _, v := range s {
import "os" f(v)
import "strconv" }
}
func main() {
Each(os.Args[1:], func(v string) { func PrintErrorMessage() {
OnPanic(PrintErrorMessage)( if x := recover(); x != nil {
UseNumericParam(v, func(i int) { Printf("no defined value for %v\n", x)
Printf("%v!: %v\n", i, Factorial(i)) }
})) }
})
} func Factorial(n int) (r int) {
switch {
func UseNumericParam(v string, f func(i int)) func() { case n < 0:
return func() { panic(n)
if x, e := strconv.Atoi(v); e == nil { case n == 0:
f(x) r = 1
} else { default:
panic(v) r = n * Factorial(n - 1)
} }
} return
} }

func OnPanic(e func()) func(func()) {


return func(f func()) {
defer e()
f()
}
}
RECURSIVE FACTORIALS

package main func Each(s []string, f func(string)) {


import . "fmt" for _, v := range s {
import "os" f(v)
import "strconv" }
}
func main() {
Each(os.Args[1:], func(v string) { func PrintErrorMessage() {
OnPanic(PrintErrorMessage)( if x := recover(); x != nil {
UseNumericParam(v, func(i int) { Printf("no defined value for %v\n", x)
Printf("%v!: %v\n", i, Factorial(i)) }
})) }
})
} func Factorial(n int) (r int) {
switch {
func UseNumericParam(v string, f func(i int)) func() { case n < 0:
return func() { panic(n)
if x, e := strconv.Atoi(v); e == nil { case n == 0:
f(x) r = 1
} else { default:
panic(v) r = n * Factorial(n - 1)
} }
} return
} }

func OnPanic(e func()) func(func()) {


return func(f func()) {
defer e()
f()
}
}
RECURSIVE FACTORIALS

package main func Each(s []string, f func(string)) {


import . "fmt" for _, v := range s {
import "os" f(v)
import "strconv" }
}
func main() {
Each(os.Args[1:], func(v string) { func PrintErrorMessage() {
OnPanic(PrintErrorMessage)( if x := recover(); x != nil {
UseNumericParam(v, func(i int) { Printf("no defined value for %v\n", x)
Printf("%v!: %v\n", i, Factorial(i)) }
})) }
})
} func Factorial(n int) (r int) {
switch {
func UseNumericParam(v string, f func(i int)) func() { case n < 0:
return func() { panic(n)
if x, e := strconv.Atoi(v); e == nil { case n == 0:
f(x) r = 1
} else { default:
panic(v) r = n * Factorial(n - 1)
} }
} return
} }

func OnPanic(e func()) func(func()) {


return func(f func()) {
defer e()
f()
}
}
RECURSIVE FACTORIALS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
Each(os.Args[1:], func(v string) {
OnPanic(PrintErrorMessage)( func PrintErrorMessage() {
UseNumericParam(v, func(i int) { if x := recover(); x != nil {
Printf("%v!: %v\n", i, Factorial(i)) Printf("no defined value for %v\n", x)
})) }
}) }
}
func Factorial(n int) (r int) {
func UseNumericParam(v string, f func(i int)) func() { switch {
return func() { case n < 0:
if x, e := strconv.Atoi(v); e == nil { panic(n)
f(x) case n == 0:
} else { r = 1
panic(v) default:
} r = n * Factorial(n - 1)
} }
} return
}
func OnPanic(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
RECURSIVE FACTORIALS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
Each(os.Args[1:], func(v string) {
OnPanic(PrintErrorMessage)( func PrintErrorMessage() {
UseNumericParam(v, func(i int) { if x := recover(); x != nil {
Printf("%v!: %v\n", i, Factorial(i)) Printf("no defined value for %v\n", x)
})) }
}) }
}
func Factorial(n int) (r int) {
func UseNumericParam(v string, f func(i int)) func() { switch {
return func() { case n < 0:
if x, e := strconv.Atoi(v); e == nil { panic(n)
f(x) case n == 0:
} else { r = 1
panic(v) default:
} r = n * Factorial(n - 1)
} }
} return
}
func OnPanic(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
RECURSIVE FACTORIALS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
Each(os.Args[1:], func(v string) {
OnPanic(PrintErrorMessage)( func PrintErrorMessage() {
UseNumericParam(v, func(i int) { if x := recover(); x != nil {
Printf("%v!: %v\n", i, Factorial(i)) Printf("no defined value for %v\n", x)
})) }
}) }
}
func Factorial(n int) (r int) {
func UseNumericParam(v string, f func(i int)) func() { switch {
return func() { case n < 0:
if x, e := strconv.Atoi(v); e == nil { panic(n)
f(x) case n == 0:
} else { r = 1
panic(v) default:
} r = n * Factorial(n - 1)
} }
} return
}
func OnPanic(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
RECURSIVE FACTORIALS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
Each(os.Args[1:], func(v string) {
OnPanic(PrintErrorMessage)( func PrintErrorMessage() {
UseNumericParam(v, func(i int) { if x := recover(); x != nil {
Printf("%v!: %v\n", i, Factorial(i)) Printf("no defined value for %v\n", x)
})) }
}) }
}
func Factorial(n int) (r int) {
func UseNumericParam(v string, f func(i int)) func() { switch {
return func() { case n < 0:
if x, e := strconv.Atoi(v); e == nil { panic(n)
f(x) case n == 0:
} else { r = 1
panic(v) default:
} r = n * Factorial(n - 1)
} }
} return
}
func OnPanic(e func()) func(func()) {
return func(f func()) {
defer e()
f()
}
}
CACHING RESULTS

FUNCTIONS
IN

MATHEMATICS
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
Each(os.Args[1:], func(v string) {
OnPanic(PrintErrorMessage)( func OnPanic(e func()) func(func()) {
UseNumericParam(v, func(i int) { return func(f func()) {
Printf("%v!: %v\n", i, Factorial(i)) defer e()
})) f()
}) }
} }

func PrintErrorMessage() { var cache map[int] int = make(map[int] int)


if x := recover(); x != nil {
Printf("no defined value for %v\n", x) func Factorial(n int) (r int) {
} if r = cache[n]; r == 0 {
} switch {
case n < 0:
func UseNumericParam(v string, f func(i int)) func() { panic(n)
return func() { case n == 0:
if x, e := strconv.Atoi(v); e == nil { r = 1
f(x) default:
} else { r = n * Factorial(n - 1)
panic(v) }
} cache[n] = r
} }
} return
}
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
Each(os.Args[1:], func(v string) {
OnPanic(PrintErrorMessage)( func OnPanic(e func()) func(func()) {
UseNumericParam(v, func(i int) { return func(f func()) {
Printf("%v!: %v\n", i, Factorial(i)) defer e()
})) f()
}) }
} }

func PrintErrorMessage() { var cache map[int] int = make(map[int] int)


if x := recover(); x != nil {
Printf("no defined value for %v\n", x) func Factorial(n int) (r int) {
} if r = cache[n]; r == 0 {
} switch {
case n < 0:
func UseNumericParam(v string, f func(i int)) func() { panic(n)
return func() { case n == 0:
if x, e := strconv.Atoi(v); e == nil { r = 1
f(x) default:
} else { r = n * Factorial(n - 1)
panic(v) }
} cache[n] = r
} }
} return
}
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
Each(os.Args[1:], func(v string) {
OnPanic(PrintErrorMessage)( func OnPanic(e func()) func(func()) {
UseNumericParam(v, func(i int) { return func(f func()) {
Printf("%v!: %v\n", i, Factorial(i)) defer e()
})) f()
}) }
} }

func PrintErrorMessage() { var cache map[int] int = make(map[int] int)


if x := recover(); x != nil {
Printf("no defined value for %v\n", x) func Factorial(n int) (r int) {
} if r = cache[n]; r == 0 {
} switch {
case n < 0:
func UseNumericParam(v string, f func(i int)) func() { panic(n)
return func() { case n == 0:
if x, e := strconv.Atoi(v); e == nil { r = 1
f(x) default:
} else { r = n * Factorial(n - 1)
panic(v) }
} cache[n] = r
} }
} return
}
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
Each(os.Args[1:], func(v string) {
OnPanic(PrintErrorMessage)( func OnPanic(e func()) func(func()) {
UseNumericParam(v, func(i int) { return func(f func()) {
Printf("%v!: %v\n", i, Factorial(i)) defer e()
})) f()
}) }
} }

func PrintErrorMessage() { var cache map[int] int = make(map[int] int)


if x := recover(); x != nil {
Printf("no defined value for %v\n", x) func Factorial(n int) (r int) {
} if r = cache[n]; r == 0 {
} switch {
case n < 0:
func UseNumericParam(v string, f func(i int)) func() { panic(n)
return func() { case n == 0:
if x, e := strconv.Atoi(v); e == nil { r = 1
f(x) default:
} else { r = n * Factorial(n - 1)
panic(v) }
} cache[n] = r
} }
} return
}
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
Each(os.Args[1:], func(v string) {
OnPanic(PrintErrorMessage)( func OnPanic(e func()) func(func()) {
UseNumericParam(v, func(i int) { return func(f func()) {
Printf("%v!: %v\n", i, Factorial(i)) defer e()
})) f()
}) }
} }

func PrintErrorMessage() { var cache map[int] int = make(map[int] int)


if x := recover(); x != nil {
Printf("no defined value for %v\n", x) func Factorial(n int) (r int) {
} if r = cache[n]; r == 0 {
} switch {
case n < 0:
func UseNumericParam(v string, f func(i int)) func() { panic(n)
return func() { case n == 0:
if x, e := strconv.Atoi(v); e == nil { r = 1
f(x) default:
} else { r = n * Factorial(n - 1)
panic(v) }
} cache[n] = r
} }
} return
}
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
c := make(Cache)
Each(os.Args[1:], func(v string) { func OnPanic(e func()) func(func()) {
OnPanic(PrintErrorMessage)( return func(f func()) {
UseNumericParam(v, func(i int) { defer e()
Printf("%v!: %v\n", i, c.Factorial(i)) f()
})) }
}) }
}
type Cache map[int] int
func PrintErrorMessage() {
if x := recover(); x != nil { func (c Cache) Factorial(n int) (r int) {
Printf("no defined value for %v\n", x) if r = c[n]; r == 0 {
} switch {
} case n < 0:
panic(n)
func UseNumericParam(v string, f func(i int)) func() { case n == 0:
return func() { r = 1
if x, e := strconv.Atoi(v); e == nil { default:
f(x) r = n * c.Factorial(n - 1)
} else { }
panic(v) c[n] = r
} }
} return
} }
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
c := make(Cache)
Each(os.Args[1:], func(v string) { func OnPanic(e func()) func(func()) {
OnPanic(PrintErrorMessage)( return func(f func()) {
UseNumericParam(v, func(i int) { defer e()
Printf("%v!: %v\n", i, c.Factorial(i)) f()
})) }
}) }
}
type Cache map[int] int
func PrintErrorMessage() {
if x := recover(); x != nil { func (c Cache) Factorial(n int) (r int) {
Printf("no defined value for %v\n", x) if r = c[n]; r == 0 {
} switch {
} case n < 0:
panic(n)
func UseNumericParam(v string, f func(i int)) func() { case n == 0:
return func() { r = 1
if x, e := strconv.Atoi(v); e == nil { default:
f(x) r = n * c.Factorial(n - 1)
} else { }
panic(v) c[n] = r
} }
} return
} }
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
f := MakeFactorial()
Each(os.Args[1:], func(v string) { func OnPanic(e func()) func(func()) {
OnPanic(PrintErrorMessage)( return func(f func()) {
UseNumericParam(v, func(i int) { defer e()
Printf("%v!: %v\n", i, f(i)) f()
})) }
}) }
}
func MakeFactorial() (f func(int) int) {
func PrintErrorMessage() { c := make(map[int] int)
if x := recover(); x != nil { return func(n int) (r int) {
Printf("no defined value for %v\n", x) if r = c[n]; r == 0 {
} switch {
} case n < 0:
panic(n)
func UseNumericParam(v string, f func(i int)) func() { case n == 0:
return func() { r = 1
if x, e := strconv.Atoi(v); e == nil { default:
f(x) r = n * f(n - 1)
} else { }
panic(v) c[n] = r
} }
} return
} }
}
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
f := MakeFactorial()
Each(os.Args[1:], func(v string) { func OnPanic(e func()) func(func()) {
OnPanic(PrintErrorMessage)( return func(f func()) {
UseNumericParam(v, func(i int) { defer e()
Printf("%v!: %v\n", i, f(i)) f()
})) }
}) }
}
func MakeFactorial() (f func(int) int) {
func PrintErrorMessage() { c := make(map[int] int)
if x := recover(); x != nil { return func(n int) (r int) {
Printf("no defined value for %v\n", x) if r = c[n]; r == 0 {
} switch {
} case n < 0:
panic(n)
func UseNumericParam(v string, f func(i int)) func() { case n == 0:
return func() { r = 1
if x, e := strconv.Atoi(v); e == nil { default:
f(x) r = n * f(n - 1)
} else { }
panic(v) c[n] = r
} }
} return
} }
}
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
f := MakeFactorial()
Each(os.Args[1:], func(v string) { func OnPanic(e func()) func(func()) {
OnPanic(PrintErrorMessage)( return func(f func()) {
UseNumericParam(v, func(i int) { defer e()
Printf("%v!: %v\n", i, f(i)) f()
})) }
}) }
}
func MakeFactorial() (f func(int) int) {
func PrintErrorMessage() { c := make(map[int] int)
if x := recover(); x != nil { return func(n int) (r int) {
Printf("no defined value for %v\n", x) if r = c[n]; r == 0 {
} switch {
} case n < 0:
panic(n)
func UseNumericParam(v string, f func(i int)) func() { case n == 0:
return func() { r = 1
if x, e := strconv.Atoi(v); e == nil { default:
f(x) r = n * f(n - 1)
} else { }
panic(v) c[n] = r
} }
} return
} }
}
CACHING RESULTS

package main func Each(s []string, f func(string)) {


import . "fmt" if len(s) > 0 {
import "os" f(s[0])
import "strconv" Each(s[1:], f)
}
func main() { }
f := MakeFactorial()
Each(os.Args[1:], func(v string) { func OnPanic(e func()) func(func()) {
OnPanic(PrintErrorMessage)( return func(f func()) {
UseNumericParam(v, func(i int) { defer e()
Printf("%v!: %v\n", i, f(i)) f()
})) }
}) }
}
func MakeFactorial() (f func(int) int) {
func PrintErrorMessage() { c := make(map[int] int)
if x := recover(); x != nil { return func(n int) (r int) {
Printf("no defined value for %v\n", x) if r = c[n]; r == 0 {
} switch {
} case n < 0:
panic(n)
func UseNumericParam(v string, f func(i int)) func() { case n == 0:
return func() { r = 1
if x, e := strconv.Atoi(v); e == nil { default:
f(x) r = n * f(n - 1)
} else { }
panic(v) c[n] = r
} }
} return
} }
}

You might also like