- A Web consultant: Full-Stack, clojure{,script}, ruby{, on rails}, javascript, react
- A CodeMentor Xpert (You can hire me!)
Are you ready for a journey into the wonderland of Functional Programming?
Javascript
function foo() { return 42}
var bar = function() { return 43}
x = [foo(), bar()]
EcmaScript6
baz = () => 42
baz()
Clojure
(defn foox [] 42)
(def bax (fn [] 43))
[(foox) (bax)]
Ruby
def foow
42
end
baw = ->() { 43 }
[foow(), baw[]]
In function languages, you can create anonymous functions i.e. functions that don’t have a name.
Javascript
[1,2,3].map(function(x) { return x + 1})
EcmaScript6
[1,2,3].map((x) => x+1)
Clojure
(map inc [1 2 3])
Ruby
[1,2,3].map {|x|
x + 1
}
An important function in FP is partial
(or curry
).
partial
takes a function and a list of arguments and returns a function where some arguments are fixed.
Let’s see it in action!
Javascript
We are going to use Ramda.
function add(x, y) { return x + y}
var add10 = R.partial(add, [10])
add10(19)
EcmaScript6
const add = (x, y) => x + y
const add10 = R.partial(add, [10])
add10(19)
Clojure
(defn add [x y] (+ x y))
(let [add10 (partial add 10)]
(add10 32))
Ruby
In ruby, it’s called curry
.
add = ->(x,y) do x + y end
add10 = add.curry.(10)
add10.(9)
Let’s write our own version of partial
:
in ES6
partial = () => 1
If you prefer you can write it in clojure
:
(defn my-partial [f x])
or in ruby:
def partial(f, x)
end
partial = (f, x) => (y) => f(x, y)
partial(add, 10)(9)
Let’s compare map
and for
in javascript.
With map
, you don’t deal with low-level details
You only express what to do with each element of the array.
[1,2,3].map(x => x + 1)
With for
, you have deal with low-level details.
You have to express:
const arr = [1,2,3]
const f = x => x + 1
let retArr = []
for(let i = 0; i < arr.length; i++) {
retArr.push(f(arr[i]))
}
retArr
A pure function
Pure functions are much simpler
This function depends on a global parameter
const N = 1e9
const rand = () => Math.round(N*Math.random())
rand()
Let’s rewrite it as a pure function
const rand = (max) => Math.round(max*Math.random())
rand(1e9)
This function writes the error to the console in case of a failure.
How will you test such a function?
const trySomething = (x) => {
if (x) {
return x*42
}
console.log(`I cannot do ${x}`)
}
trySomething()
Let’s rewrite it as a pure function.
We will return an array with:
trySomethingPure = (x) => {
if (x) {
return ["ok", x*42]
}
return ["error", `I cannot do ${x}`]
}
trySomethingPure(1)
In non-functional languages, the default API mutates our objects.
You modify b
and in fact, you modify also a
!
In javascript:
const a = {size: 42};
b = a;
b.size = 43
a
In ruby:
a = {size: 42}
b = a
b['size'] = 33
a
In clojure, no problem: clojure data structures are immutable!
Instead of mutating an object, you create a new version of it.
Usually, this is not effective.
But some languages (e.g. clojure) support immutability natively and provide an effective implementation of persistent data structure.
Clojure
(let [a {:size 42}
b a
c (assoc b :size 33)]
[a b c])
In order to enjoy immutability in Javascript, you have to use a library like immutable.js
a = Immutable.fromJS({size: {shoes: 42 }})
b = a.setIn(["size", "shoes"], 43)
a
There is a immutable library available for ruby
In functional languages, some sequences are lazy.
The elements are evaluated only when we really need them.
Let’s see some examples in clojure
:
(def lazy-a (map (fn [x] (println "val:" x) x) [1 2 3]))
Nothing is printed, until we access the elements…
(nth lazy-a 0)
Nothing prevents from lazy sequences to be infinite!
All the natural numbers
(def natural-numbers (range))
(take 10 natural-numbers)
Infinite repetition of an element
(def infinite-hello (repeat :hello))
(nth infinite-hello 100)
Don’t try to count the elements!
An infinite sequence of random numbers
(def infinite-random-numbers (repeatedly (partial rand-int 100)))
(nth infinite-random-numbers 345)
(+ 1 2 3)
instead of 1 + 2 + 3
or +(1,2,3)
Many functional languages are transpiled in Javascript: Clojure, Scala, F#, Ocaml.
The power of Clojure in the browser!
ReactDOM.render(React.createElement(Square, {value: 42,
onClick: () => alert("clicked")}), klipse_container)
<Square
value={26}
onClick={() => alert("clicked")}
/>
Exercise: display the value when the square is clicked
class SquareLogic extends React.Component {
constructor(props) {
super(props)
this.state = {
val: 10
}
}
increment() {
let state = R.assoc('val', this.state.val + 1, this.state)
this.setState(state)
}
render() {
return (
<Square value={this.state.val}
onClick= {() => this.increment()}/>
)
}
}
window.SquareLogic = SquareLogic
<SquareLogic/>
Three principles (constraints):
Many Positive consequences:
Component
const mapDispatchToProps = (dispatch) => ({
onClick() {
dispatch(incrementSquareValue())
}
})
const mapStateToProps = (state) => ({
value: state.square.value
})
window.SquareRedux = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(Square)
Actions
incrementSquareValue = () => ({
type: 'INCREMENT_SQUARE_VALUE'
})
Reducers
square = (state={value: 0}, action) => {
switch(action.type) {
case 'INCREMENT_SQUARE_VALUE':
return R.assoc('value', state.value + 1, state)
default:
return state
}
}
app = Redux.combineReducers({square: square})
The store
store = Redux.createStore(app)
The App
<ReactRedux.Provider store={store}>
<SquareRedux/>
</ReactRedux.Provider>
Playground
// store.dispatch(incrementSquareValue())
// store.getState()
When we need to write a (relatively small) worker that is part of a computation pipe, we need a language:
Examples: Spark (scala), Storm (Clojure), Onyx (Clojure)
powered by Klipse /