scato
July 05, 2017
330

# Functional Programming for "Dummies"

Should have been called: An impractical introduction to Haskell for experienced PHP developers.

July 05, 2017

## Transcript

1. Functional Programming
for Dummies*
*) people without a degree in Computer Science

2. Functional
Programming
is...

3. “Functional” Programming
function set_id(\$record, \$id)
{
\$record['id'] = \$id;
}

4. 1. Properties of the Language
2. Common Practices
3. Theoretical Framework

5. 1. Referential Transparency
2. Pointfree Programming
3. Algebraic Data Types

6. Referential
Transparency

7. Referential Transparency
An expression is referentially transparent if you can
replace that expression with its corresponding value without
changing the behavior of the program.

8. Referential Transparency
function main()
{
\$i = 41;
\$i++;
return \$i;
}

9. Referential Transparency
function main()
{
\$i = 41;
\$i++; // <- evaluates to 41
return \$i;
}

10. Referential Transparency
function main()
{
\$i = 41;
41;
return \$i;
}

11. Referential Transparency
function main()
{
\$i = 41;
\$j = \$i + 1;
return \$j;
}

12. Referential Transparency
function main()
{
\$i = 41;
\$j = \$i + 1; // <- evaluates to 42
return \$j;
}

13. Referential Transparency
function main()
{
\$i = 41;
\$j = 42;
return \$j;
}

14. Referential Transparency
Referential transparency means that when you read code, you
only have to think of the outcome of an expression. You can
forget about state, and the way that evaluating an
expression can change that state.

15. 1. Pure Functions
2. Immutability
3. Immutable Data Structures
4. Recursion

16. Pure Functions
function average(\$a, \$b)
{
return (\$a + \$b) / 2;
}

17. Immutability
function average(\$a, \$b)
{
\$total = 0;
\$total += \$a; // <- fail!
\$total += \$b; // <- fail!
return \$total / 2;
}

18. Immutability
function average(\$a, \$b)
{
\$total = \$a + \$b;
return \$total / 2;
}

19. Immutable Data Structures
\$x = 1;
\$y = 2;
\$p = [0, 2];
\$p[2] = 5; // <- fail

20. Immutable Data Structures
\$xs = [1, [2, [3, null]]];
tail(\$xs) // <- [2, [3, null]]
\$empty = null;

21. Recursion
To understand recursion, you must first understand
recursion.

22. Recursion
function average(\$xs)
{
return sum(\$xs) / length(\$xs);
}

23. Recursion
function length(\$xs)
{
\$length = 0;
foreach (\$xs as \$x) {
\$length += 1; // <- fail!
}
return \$length;
}

24. Recursion
function sum(\$xs)
{
\$sum = 0;
foreach (\$xs as \$x) {
\$sum += \$x; // <- fail!
}
return \$sum;
}

25. Recursion
function length(\$xs)
{
if (\$xs === null) {
return 0;
}
return 1 + length(tail(\$xs));
}

26. Recursion
function sum(\$xs)
{
if (\$xs === null) {
return 0;
}
}

27. Recursion
average(\$xs)

28. Recursion
average(\$xs)

29. Recursion
average([1, [2, [3, null]]])

30. Recursion
average([1, [2, [3, null]]])

31. Recursion
sum([1, [2, [3, null]]]) / length([1, [2, [3, null]]])

32. Recursion
sum([1, [2, [3, null]]]) / length([1, [2, [3, null]]])

33. Recursion
(head([1, [2, [3, null]]]) + sum(tail([1, [2, [3, null]]])))
/ (1 + length(tail([1, [2, [3, null]]])))

34. Recursion
(head([1, [2, [3, null]]]) + sum(tail([1, [2, [3, null]]])))
/ (1 + length(tail([1, [2, [3, null]]])))

35. Recursion
(1 + sum(tail([1, [2, [3, null]]]))) / (1 + length(tail([1,
[2, [3, null]]])))

36. Recursion
(1 + sum(tail([1, [2, [3, null]]]))) / (1 + length(tail([1,
[2, [3, null]]])))

37. Recursion
(1 + sum([2, [3, null]])) / (1 + length(tail([1, [2, [3,
null]]])))

38. Recursion
(1 + sum([2, [3, null]])) / (1 + length(tail([1, [2, [3,
null]]])))

39. Recursion
(1 + sum([2, [3, null]])) / (1 + length([2, [3, null]]))

40. Recursion
(1 + sum([2, [3, null]])) / (1 + length([2, [3, null]]))

41. Recursion
(1 + 2 + sum([3, null])) / (1 + 1 + length([3, null]))

42. Recursion
(1 + 2 + sum([3, null])) / (1 + 1 + length([3, null]))

43. Recursion
(1 + 2 + 3 + sum(null)) / (1 + 1 + 1 + length(null))

44. Recursion
(1 + 2 + 3 + sum(null)) / (1 + 1 + 1 + length(null))

45. Recursion
(1 + 2 + 3 + 0) / (1 + 1 + 1 + 0)

46. Recursion
(1 + 2 + 3 + 0) / (1 + 1 + 1 + 0)

47. Recursion
6 / 3

48. Recursion
6 / 3

49. Recursion
2

50. Recursion
2

51. Recursion
function sum(\$xs)
{
if (\$xs === null) {
return 0;
}
}

52. Recursion
function sum(\$xs)
{
if (\$xs === null) {
return 0;
}
return head(\$xs) + sum(tail(\$xs)); // <- recursion
}

53. Recursion
function sum(\$xs, \$start)
{
if (\$xs === null) {
return \$start;
}
return sum(tail(\$xs),
head(\$xs) + \$start); // <- tail recursion
}

54. Recursion

55. Pointfree
Programming

56. 1. Currying
2. Partial Application
3. Higher Order Functions
4. Functional Composition

57. Higher Order Functions
A higher order function is a function that accepts a
function as one of its parameters and/or returns a function.

58. Higher Order Functions
function sum(xs) {
if (xs === null) {
return 0;
}
}

59. Higher Order Functions
const sum = xs =>
xs === null ? 0 : head(xs) + sum(tail(xs));

60. Higher Order Functions
const add = (x, y) =>
x + y;

61. Higher Order Functions
const add = x => y => // <- currying
x + y;

62. Higher Order Functions
const add = x => y =>
x + y;
add(1)(2) // <- evaluates to 3

63. Higher Order Functions
const add = x => y =>
x + y;
add(1) // <- evaluates to y => 1 + y

64. Higher Order Functions
const add = x => y =>
x + y;

65. Higher Order Functions
const add = x => y =>
x + y;
add(1) // <- higher order function

66. Higher Order Functions
const add = x => y =>
x + y;
const sum = xs =>

67. Higher Order Functions
const foldr = f => z => xs =>
xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))

68. Higher Order Functions
const foldr = f => z => xs =>
xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))
const sum = xs =>

69. Higher Order Functions
const foldr = f => z => xs =>
xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))
const sum = xs =>

70. Higher Order Functions
const foldr = f => z => xs =>
xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))
const sum = xs =>

71. Higher Order Functions
const foldr = f => z => xs =>
xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))
const sum = xs =>

72. Higher Order Functions
const foldr = f => z => xs =>
xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))

73. Higher Order Functions
const map = f => xs =>
xs === null ? null : [f(head(xs)), map(f)(tail(xs))];
const compose = f => g =>
x => f(g(x)); // <- functional composition
const constant = x => y =>
x;

74. Higher Order Functions
const ones = map(constant(1));
const length = compose(sum)(ones);

75. Pointfree Programming
const ones = map(constant(1));
const length = compose(sum)(ones);
// not one single parameter

76. Pointfree Programming
Topology (a branch of mathematics) works with spaces
composed of points, and functions between those spaces. So a
pointfree definition of a function is one which does not
explicitly mention the points (values) of the space on which
the function acts.

77. Algebraic
Data Types

78. Algebraic Data Types
Just like there are rules for manipulating numbers, there
are rules for manipulating types.

79. 1. Sum Types
2. Product Types
3. Type Constructors
4. Recursive Type Definitions
5. Pattern Matching

80. Sum Types
data Bool = True | False
not :: Bool -> Bool
not True = False
not False = True

81. Product Types
data Point = Point Int Int
translate :: Point -> Point -> Point
translate (Point dx dy) (Point x y) =
Point (x + dx) (y + dy)

82. Type Constructors
data Maybe a = Nothing | Just a
isNothing :: Maybe a -> Bool
isNothing (Just a) = False
isNothing Nothing = True

83. Recursive Type Definitions
data List a = Nil | Cons a (List a)
length :: List a -> Int
length Nil = 0
length (Cons x xs) = 1 + length xs

84. Pattern Matching
translate (Point dx dy) (Point x y) =
Point (x + dx) (y + dy)
length Nil = 0
length (Cons x xs) = 1 + length xs

85. 6. Hindley-Milner Type System

86. Hindley-Milner Type System
The Hindley-Milner Type System is a system that allows you
to do type inference on lambda calculus, in order to derive
the most generic type of every expression in a program.

87. Type Inference
data List a = Nil | Cons a (List a)
-- length :: List a -> Int
length Nil = 0
length (Cons x xs) = 1 + length xs

88. Type Inference
data List a = Nil | Cons a (List a)
-- length :: List a -> Int
length Nil = 0
length (Cons x xs) = "1" ++ length xs -- <- oops
-- No instance for (Num [Char]) arising from the literal ‘0’

89. Type Inference
data List a = Nil | Cons a (List a)
length :: List a -> Int
length Nil = 0
length Cons x xs = "1" ++ length xs -- <- oops
-- Couldn't match expected type ‘Int’
-- with actual type ‘[Char]’

90. Type Inference
data List a = Nil | Cons a (List a)
length :: List a -> Int
length Nil = 0
length Cons x xs = length -- <- totale nonsense
-- Couldn't match expected type ‘Int’
-- with actual type ‘List a0 -> Int’

91. Type Inference
the algorithm (roughly):
1. assign type variables to all expressions (both left and
right of an ‘=’)
2. start at the top
3. move to the next piece of code that imposes a constraint
4. unify the two type variables
5. go back to step 3, until you reach the bottom

92. Type Inference
constraints:
● the left and right hand side of ‘=’ must have the same
type
● the result of ‘+’ has the same type as the expressions on
either side
● applying a function with type a0 -> a1 is only valid on a
parameter of type a0
● applying a function with type a0 -> a1 always produces a
result of type a1

93. Type Inference
unifying type variables:
● if a0 = Int
and a1 = a0
then a1 = Int
● if a2 = Maybe Int
and a3 = Maybe a4
and a2 = a3
then a4 = Int

94. Hindley-Milner Type System
(->) is a Type Constructor

95. Category
Theory

Once you understand monads for yourself, you lose the
ability to explain them to others. – Douglas Crockford

97. 1. Functors
2. Monoid
3. Applicatives

98. 1. Functors
2. Monoid
3. Applicatives

99. The Maybe Functor
class Functor f where
fmap :: (a -> b) -> f a -> f b
data Maybe a = Nothing | Just a
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)

100. The Maybe Functor
isEven x = x `mod` == 0
fmap isEven (Just 1) -- Just False
fmap isEven Nothing -- Nothing

101. The Maybe Functor
isEven x = x `mod` == 0
maybeEven = fmap isEven
maybeEven (Just 1) -- Just False
maybeEven Nothing -- Nothing

102. 0. Category Theory

103. Category Theory for Programmers
Bartosz Milewski

104. Category Theory

105. Derp
examples of categories:
● Grp – a category with groups for objects and group
● Set – the category whose objects are sets, and where
functions form the morphisms

106. Functors
A functor is a mapping from one category to another.

107. Functors

108. Functors

109. Functor Laws
category theory demands the following:
fmap id = id
fmap (p . q) = (fmap p) . (fmap q)

110. Functor Laws

111. Functor Laws

112. The Maybe Functor
-- fmap id = id
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)

113. The Maybe Functor
-- fmap id Nothing = id Nothing
-- Nothing = Nothing
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)

114. The Maybe Functor
-- fmap id (Just a) = id (Just a)
-- Just (id a) = Just a
-- Just a = Just a
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)

115. The Maybe Functor
-- fmap (p . q) = (fmap p) . (fmap q)
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)

116. The Maybe Functor
-- fmap (p . q) Nothing = ((fmap p) . (fmap q)) Nothing
-- Nothing = (fmap p) ((fmap q) Nothing)
-- Nothing = (fmap p) Nothing
-- Nothing = Nothing
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)

117. The Maybe Functor
-- fmap (p . q) (Just a) = ((fmap p) . (fmap q)) (Just a)
-- Just ((p . q) a) = (fmap p) ((fmap q) (Just a))
-- Just (p (q a)) = (fmap p) (Just (q a))
-- Just (p (q a)) = Just (p (q a))
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)

118. Category Theory

119. 1. Referential Transparency
2. Pointfree Programming
3. Algebraic Data Types

120. Thnx
@scataco