Upload
timothy-roberts
View
50
Download
0
Embed Size (px)
Citation preview
Doctor IterateOR HOW I LEARNED TO STOP WORRYING AND LOVE HIGHER-ORDER FUNCTIONS
http://www.slideshare.net/TimothyRoberts8/dr-iterate-or-how-i-learned-to-stop-worrying-and-love-higherorder-functions
Tim Roberts
@cirscagithub.com/beardedtim
Okay MentorBetter Older Brother
JavaScript EvangelistFunctional-ish Developer
Programming is Hard
The Fun Part
Joe Armstrong - Coders At Work
I think the lack of reusability comes in object-oriented languages, not functional
languages. Because the problem with object-oriented languages is
they’ve got all this implicit environment that they carry
around with them.
OOP-ishvar Student = function(name, gpa, level) {
this.name = name
this.gpa = gpa
this.level = level
}
OOP-ishStudent.prototype.getName = function(){
return this.name
}
Student.prototype.getGpa = function(){
return this.gpa
}
Student.prototype.raiseLevel = function(){
this.level = this.level + 1
}
Gary Entsminger- The Tao of Objects
Putting operations and behaviors in one place makes good sense; it’s
safer and more convenient
OOP-ishvar StudentList = function(students){
this.students = students
this.getNames = function(){/* …. */
}
this.raiseStudentsLevel = function(){/* …. */
}
}
Imperative-ishvar students = […]
var names = []
for(var = i; i < students.length; i++){
var name = students[i].getName()
names.push(name)
}
console.log(names) // Katie, Emmie, Timi, …
OOP-ishthis.getNames = function(){
var names = []for(var = i; i < this.students.length; i++){
var name = this.students[i].getName()names.push(name)
}return names
}
this.raiseStudentsLevel = function(){for(var = i; i < this.students.length; i++){
var student= this.students[i]student.raiseLevel()
}}
Simon Peyton Jones – Coders at Work
When the limestone of imperative programming is worn away, the granite
of functional programming will be
observed
OOP-ishthis.forEachStudent = function(fn){
for( var i = 0; i < this.students.length; i++){
var student = this.students[i]fn(student,i,this.students)
}
}
OOP-ish
this.getNames = function(){var names = [],
getName = function(student, i, this.students){var name = studet.getName()names.push(name)
}this.forEachStudent(getName)return names
}
OOP-ish
this.raiseLevels = function(){var raiseStudentLevel =
function(student,i,students){student.raiseLevel()
}this.forEachStudent(raiseStudentLevel)
}
OOP-ish
var TeacherList = function(teachers){
this.teachers = teachers
this.getNames = /* ….? */ }
Functional-ish
function forEach(arr,fn){for(var i = 0; i < arr.length; i++){
fn(arr[i],i,arr)}
}
Functional-ishvar studentNames = []forEach(StudentList.students,(student) => {
studentNames.push(student.getName())})var teachersNames= []forEach(TeacherList.teachers,(teacher) => {
teacherNames.push(teacher.getName())})
What Is Our Worker Doing?
Functional-ish
function map(arr,fn){var result = []for(var i = 0; i < arr.length; i++){
var newVal = fn(arr[i],i,arr)result.push(newVal)
}return result
}
Functional-ish
var studentNames = map(StudentList.students, student =>
student.getName())var teachersNames=
map(TeacherList.teachers, teacher => teacher.getName())
Regular Objects
var studentNames = map(students, student => student.name)
var teachersNames= map(teachers, teacher => teacher.name)
Regular Objects
var getName = obj => obj.name
var studentNames= map(students, getName)
var teachersNames= map(teachers, getName)
Better But Repetitive
var getName = obj => obj.name
var getAge = obj => obj.age
var getLocation = obj => obj.location
What Are We Actually Doing?
var pluck = key => obj =>obj[key]
var getName = pluck(‘name’)
var getAge = pluck(‘age’)
So What About Higher-Order Functions?
A Higher-Order Function is
A function that accepts a function:function map(arr,fn){
var result = []for(var i = 0; i < arr.length; i++){
var newVal = fn(arr[i],i,arr)result.push(newVal)
}return result
}
A Higher-Order Function is
A function that returns a function:var pluck = key => obj => obj[key]
Let’s Solve Something
https://github.com/mlotstein/StarFleet-Mine-Clearing-Exercise/blob/master/README.md
Let’s Solve Something
..A..A…A..A..
board.txt
northdelta south
west gamma
moves.txt
What Data Structure?
var Board = function(){this.board = …
this.drawBoard = function(center){/* .... */
}}
What Data Structure?
var board = …
var makeBoard = (board,center){/* .... */
}
Why Does It Matter?
Is The Board Always Correct?
Am I Touching The Board?
What’s The Contract?
Reusable Solutionsconst board = str => str.split(‘\n’)
.map(row => row.split(‘’))
..A..A…A..A..
board.txt
[[‘.’,’.’,’A’,’.’,’.’],[‘A’,’.’,’.’,’.’,’A’],[‘.’,’.’,’A’,’.’,’.’]]
const board
Reusable Solutionsconst board = str => str.split(‘\n’)
.map(row => row.split(‘’))
Get Only If…
const row = [‘.’,’.’,’A’,’.’,’.’]
const emptyIndexes = /* ….? */
Get Only If…const filter = (arr,pred) => {
const result = []for(let i = 0; i < arr.length; i++){
const item = arr[i] if(pred(item,i,arr){
result.push(item)}
}return result
}
Half Way There
const row = [‘.’,’.’,’A’,’.’,’.’]
const emptyIndexes = filter(row,char => char === ‘.’)
Map To The Rescue!
const row = [‘.’,’.’,’A’,’.’,’.’]
const emptyIndexes = row.map( (char, i) => ({ index: i, char}) )
.filter({char} => char === ‘.’)
console.log(emptyIndexes) // [{index: 0, char: ‘.’},…]
Loop ALL The Times
const row = [‘.’,’.’,’A’,’.’,’.’]
const emptyIndexes = row.map( (char, i) => ({ index: i, char}) )
.filter({char} => char === ‘.’) .map(pluck(‘index’))
console.log(emptyIndexes) // [0,1,3,4]
How Does That Help Us?const mines = board => /* ….? */
[[‘.’,’.’,’A’,’.’,’.’],[‘A’,’.’,’.’,’.’,’A’],[‘.’,’.’,’A’,’.’,’.’]]
const board
[[0,2],[1,0],[1,4],[2,0]]
const mines
How Does That Help Us?const minesFromRows = (row,y) =>
row.map((char, x) => ({location: [x,y],char})
.filter({char} => char !== ‘.’)
const mineCoords = board => board.map(minesFromRows)
.filter(row => row.length) .reduce((list,row) =>
list.concat(row),[]) .map(pluck(‘location’))
Reduce Down For What?const reduce = (arr,fn,start) => {
let result = startfor(let i = 0; i < arr.length; i++){
const curr = arr[i],pre = result
result = fn(pre,curr,i, arr)}return result
}
Reduce, Reuse, Recycle
const biggestDelta = ([x1,y1],[x2,y2] =>
[Math.max(x1,x2),Math.max(y1,y2)]
const furthestPoints =(mines,[centerX,centerY]) =>
mines.reduce(biggestDelta,[0,0])
Actually Smart People
https://www.youtube.com/channel/UCO1cgjhGzsSYb1rsB4bFe4Q
Actually Smart People
https://github.com/getify/Functional-Light-JS
Programming is Hard
http://www.slideshare.net/TimothyRoberts/dr-iterate-or-how-i-learned-to-stop-worrying-
and-love-higherorder-functions
@cirscagithub.com/beardedtim