Commit b511a7b9 authored by Tad Lispy's avatar Tad Lispy

Setup GitLab CI, update content

parent e3273df6
Pipeline #109983818 failed with stage
in 18 seconds
image: alpine
pages:
stage: deploy
script:
- mv Presentation.html public/index.html
artifacts:
paths:
- public/
only:
- master
This source diff could not be displayed because it is too large. You can view the blob instead.
---
author: Tad Lispy
title: Why is this so Terrible?
subtitle: Elements of functional programming for JavaScript developers
subtitle: Elements of Functional Programming for React.js Developers
date: 2020-01-16
---
## So what's so bad about it?
##
You want to do computation on your data,
but how can you trust your data,
when it has it's own mind?
:::::: { .columns }
##
::: { .column width="50%" height="100%" }
![](./src/tad-lispy.png){ .plain }
:::
::: { .column width="50%" height="100%" }
### Hello, I'm Tad Lispy
[tad-lispy.com](https://tad-lispy.com/)
[gitlab.com/tad-lispy](https://gitlab.com/tad-lispy/)
A software developer,
functional programming coach
<small>(available for contract)</small>
and Unix philosopher.
:::
::::::
The problem in all these cases is coupling of data and _behaviour_
(aka. methods).
##
## Essence of object - oriented programming
How can you trust your data
when it has its own mind?
# Essence of Object Oriented Programming
##
The data and the computation are coupled together:
......@@ -24,27 +44,25 @@ The data and the computation are coupled together:
[ 1, 2, 3 ].map((e) => e + 1);
```
## But what's the point?
##
Instead of
Each object is a little actor with its own state.
``` { .javascript .numberLines }
[ 1, 2, 3 ].map((e) => e + 1);
```
It exposes various methods via which other actors can communicate with it.
why not
They are all one big, happy family that interacts with one another.
``` { .javascript .numberLines }
map((e) => e + 1, [ 1, 2, 3 ])
```
##
**?**
Sounds like a powerful idea.
# The Good
## The good
##
There are some benefits of OOP.
There are some benefits of OOP
Mainly it is easy to implement stateful computation.
e.g. it is easy to implement stateful computation.
``` { .javascript
.numberLines
......@@ -52,9 +70,24 @@ Mainly it is easy to implement stateful computation.
}
```
## The bad
But then you have to keep track of implicit context
# The Bad
##
But
> many actors, each with its own state
sound complex
. . .
And it is
##
You have to keep track of implicit context
``` { .javascript
include="src/timeout.js"
......@@ -62,9 +95,31 @@ But then you have to keep track of implicit context
}
```
## The Ugly
##
When you implement a function
<small>(method is just a function attached to an object)</small>
you don't know what `this` will be.
##
So `this` is like an implicit argument.
It will only be known at the time of calling the function.
``` { .javascript
include="src/what-is-this.js"
.numberLines
}
```
# The Ugly
##
Even worse, your data starts having brain of it's own:
Even worse, your data starts having brain of its own:
``` { .javascript
include="src/reduced-to-mockery.js"
......@@ -78,6 +133,7 @@ Even worse, your data starts having brain of it's own:
include="src/reduced-to-mockery.js"
.numberLines
.fragment
data-fragment-index=2
startFrom=5
endAt=5
}
......@@ -91,7 +147,11 @@ Even worse, your data starts having brain of it's own:
}
```
## The Ugly
<small class="fragment" data-fragment-index="1">
**Hint**: It will print "Buhahaha 🥳"
</small>
##
And it may be up to no good
......@@ -109,3 +169,242 @@ And it may be up to no good
startFrom=8
}
```
. . .
Seriously, who needs this in their language?
# What's the alternative
##
Instead of
``` { .javascript .numberLines }
[ 1, 2, 3 ].map((e) => e + 1);
```
why not
``` { .javascript .numberLines }
map((e) => e + 1, [ 1, 2, 3 ])
```
**?**
##
Or instead of
``` { .javascript .numberLines }
[ 1, 2, 3 ].length;
```
why not
``` { .javascript .numberLines }
length([ 1, 2, 3 ])
```
**?**
# The Essence of Functional Programming
### Composition.
. . .
Things are simple and you can compose them
. . .
A data is a data: `a`
A function is a function: `a -> b`
Functions don't have state
##
You can compose data:
``` javascript
const a = 1
const b = 2
const composed = { a, b }
```
##
You can compose functions:
``` { .javascript
include="src/composition.js"
.numberLines
startFrom=1
endAt=10
}
```
##
Ugly?
``` { .javascript
include="src/composition.js"
.numberLines
startFrom=6
endAt=8
}
```
. . .
How about this?
``` { .javascript
include="src/composition.js"
.numberLines
startFrom=12
endAt=15
}
```
##
Or even this:
``` { .javascript
include="src/composition.js"
.numberLines
startFrom=17
}
```
##
With this setup:
``` { .javascript
include="src/composition-equivalence.js"
.numberLines
startFrom=7
endAt=9
}
```
All of these are equivalent:
``` { .javascript
include="src/composition-equivalence.js"
.numberLines
startFrom=13
}
```
##
But what if the function I want to compose takes some additional arguments?
``` javascript
function divideBy (a, b) { return b / a }
```
##
The lambda way:
``` { .javascript
include="src/partial-lambda.js"
.numberLines
startFrom=7
}
```
##
The partial way:
``` { .javascript
include="src/partial.js"
.numberLines
startFrom=11
}
```
##
The Indian cuisine way
``` { .javascript
include="src/partial-curry.js"
.numberLines
startFrom=9
}
```
. . .
<small>Just kidding. It's a way of [Haskell Brooks Curry][].</small>
##
Using **partial application** and **composition** you can model any computation, no matter how complex.
. . .
And it will almost always be easier to reason about than OOP, because no state means less complexity.
# Simplicity
##
Predictible behaviour, simple rules of composition and partial application.
##
What follows is that concerns are usually separated
### data | computation | state | effects
You can mix them **if you want to**, but by default they are separated.
# But I need my state!
##
Sure. Sometimes you do. But ask yourself how often?
##
And if you really do, be explicit about it.
If you are workin with React, use [Redux][].
<small>(or whatever else is all the hype this week)</small>
##
If you need effects (e.g. networking), use [Thunks][].
##
For presentation use functional components.
# Educate Yourself
##
- Read [Professor Frisby's Mostly Adequate Guide to Functional Programming][]
How to do FP in JS
- Come join us at [Category Theory Study Group][]
Meet some friendly people and learn the mathematical theory behind this stuff.
[Haskell Brooks Curry]: https://en.wikipedia.org/wiki/Haskell_Curry
[Category Theory Study Group]: https://www.meetup.com/fp-ams/events/267715699/
[Professor Frisby's Mostly Adequate Guide to Functional Programming]: https://mostly-adequate.gitbooks.io/mostly-adequate-guide/
[Redux]: https://redux.js.org/
[Thunks]: https://github.com/reduxjs/redux-thunk
"use strict"
// Setup
const flow = require("lodash/fp/flow")
const increment = function (number) { return number + 1 }
const double = function (number) { return number * 2 }
const compute = flow(double, increment)
// All below are equivalent:
console.log(increment(double(3)))
console.log(flow( double, increment )(3))
console.log(compute(3))
flow( double, increment, console.log )(3)
flow( compute, console.log )(3)
"use strict"
const increment = function (number) { return number + 1 }
const double = function (number) { return number * 2 }
const compute = function (number) {
return increment(double(number))
}
console.log(compute(3))
const flow = require("lodash/fp/flow")
const compute_too = flow(double, increment)
console.log(compute_too(3))
flow(compute_too, console.log)(3)
"use strict"
const flow = require("lodash/fp/flow")
const curry = require("lodash/fp/curry")
const increment = function (number) { return number + 1 }
const double = function (number) { return number * 2 }
const divideBy = curry(function (a, b) { return b / a })
const compute = flow(
double,
increment,
divideBy(3)
)
console.log(compute(4))
"use strict"
const flow = require("lodash/fp/flow")
const increment = function (number) { return number + 1 }
const double = function (number) { return number * 2 }
const divideBy = function (a, b) { return b / a }
const compute = flow(
double,
increment,
(number) => divideBy(3, number)
)
console.log(compute(4))
"use strict"
const flow = require("lodash/fp/flow")
const partial = require("lodash/fp/partial")
const increment = function (number) { return number + 1 }
const double = function (number) { return number * 2 }
const divideBy = function (a, b) { return b / a }
const compute = flow(
double,
increment,
partial(divideBy, [3])
)
console.log(compute(4))
......@@ -2,7 +2,7 @@ const stateful = {
count: 0,
poke() {
this.count = this.count + 1
if(this.count > 3) {
if (this.count > 3) {
console.log("**** you!")
} else {
console.log("a! ".repeat(this.count))
......
"use strict"
const speaker = {
name: "Tad",
name: "Tad Lispy",
introduce() {
console.log(`Hello, I'm ${this.name}!`)
}
......
"use strict"
const fn = function() { console.log(this) }
const ob = { fn, fatfn: () => fn() }
fn(4)
fn.call(3)
fn.apply(2)
fn.bind(1)
ob.fn(0)
ob.fatfn(-1)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment