240 likes | 257 Views
Functional Programming. CS/COE 1520 Jarrett Billingsley. Today:. Functional programming a (maybe new-to-you) style of coding some practical examples of it to give us some practice with the DOM so how's the project going? run into any problems?. What is it?. When you hear "functional"….
E N D
Functional Programming CS/COE 1520 Jarrett Billingsley
Today: • Functional programming • a (maybe new-to-you) style of coding • some practical examples of it • to give us some practice with the DOM • so how's the project going? run into any problems?
When you hear "functional"… • think of it in the mathematical sense. • functional programming (FP) is a coding style where… functions are black boxes. f …and their outputs only depend on the inputs. they have inputs (arguments)… in the strictest form, functional programming has no state at all, only these kinds of functions.
State • state is the collective contents of all the storage in a computer. other computers registers RAM the whole damn WORLD is state files peripherals users but state is confusing. well, that's only part of it…
Well, it's mutable state that's confusing • mutable means "can be changed";immutable meansit can't be. • the problem is when two or more things must share state. f1 t1 c1 f2 t2 c2 two functions sharing a global variable… two computers sending state over a network… two threads sharing a data structure… in all of these cases, if one "actor" misbehaves, the other one will malfunction. and it can be really damn hard to figure out who's at fault.
Side effects • a function has side effects if it changes state. console.log("bye") console.log("hi") console.log("hi") console.log("bye") I'm calling the same function with the same arguments. will I get the same output? uh, no. a side-effecting function can cause different outcomes depending on: when you call it the order of calls to it how many times you call it the phase of the moon
Pure functions: • have at least one argument • return a value computed only from the arguments • have no side effects • mathematical functions satisfy these requirements easily. + sin 3 π 8 0 5 you've been trained to create side effects, which makes it hard to think of nontrivial pure functions. but you've dealt with a whole bunch of pure functions before…
Any self-respecting language has • immutable strings! • Java and JS have immutable strings, and all their methods are pure. String name = "Jarrett Billingsley"; String[] parts = name.split(" "); String s = parts[1] + ", " + parts[0]; String t = s.toUpperCase(); every method takes one or more strings and produces a new string based on the inputs. you can't modify strings, so once you have a string, no one else can mess it up.
But without input or output… • if your program can't interact with the world… • then your computer is just a fancy heater we have to step outside the pure subset of a language to interact with the user, store files, communicate over the network etc. but purity is a good thing to strive for. CPU running beautiful code
"Effectively pure" • for the pedantic, a pure function uses no mutable state at all… • not even local variables! • so no loops, only recursion • but we're using an imperative language, and loops are more natural. functioncountZeros(arr) { var count = 0; for(var v ofarr) { if(v == 0) count++; } return count; } although we use a mutable variable and a loop where v takes on multiple values… from outside this function, it looks pure.
First-class functionsOK enough theory, time for some practice
Out on their own • we say that JS has first-class functions class Math sin() var sin = Math.sin; in JS, there are no such restrictions. functions are values just like numbers, strings, and objects. in Java, functions are "trapped" inside classes. you can't* make a variable that holds a function. this makes it easy and natural to pass around actions just like anything else.
Wait, passing around actions? • well… yeah. let's think about comparison-based sorting algorithms. for(i = 0toA.length - 1) for(j = i down to1) if(A[j - 1] > A[j]) swap(A, j, j - 1) else break by changing this comparison, we can choose the kind of sorting, the direction of the sort etc. but do we really want to write a new sorting function every time we want to change the comparison? there is a key decision in this algorithm that changes how it behaves.
Parameterizing decisions • by passing a function as a parameter, we can customize the behavior of this sorting function. the function we pass is called a predicate. function sort(A, wrongOrder) for(i = 0toA.length - 1) for(j = i down to1) if(wrongOrder(A[j-1], A[j])) swap(A, j, j-1) else break A = [3, 9, 2, 1, 6] sort(A, function(a, b) { return a < b })
In JS • the Array.prototype.sort() method takes a sorting predicate. vararr = [2, 7, 5, 4, 3, 9, 0, 1, 6, 8] arr.sort(function(a, b) { if(a < b) return1 elseif(a > b) return -1 elsereturn0 }) console.log(arr.join(', ')) the predicate behaves like Java's compareTo() method – negative for less, positive for greater, 0 for equal.
Big AND • you want to check if all items in an array satisfy some condition. • let's say… all items in the range [0, 100]. vararr = [17, 34, 55, 10, 2, 9, 98] varallInRange = true for(var v ofarr) { if(!(v >= 0 && v <= 100)) { allInRange = false break } } if(allInRange) { // do something } this is verbose and likely needed in other places. let's abstract it.
The initial goal • let's say we want our calling code to look like this: if(allInRange(arr, 0, 100)) { // do something } okay, so let's take the previous code and make it into a function. (really, let's do it.) now we have this function, but… what if I wanted an exclusive range? what if I only wanted to check an upper bound? what if I wanted to check the lengths of strings? this function is poorly abstracted. we have hard-coded a decision and limited its use.
Moving the goalposts (to a better place) • now let's make our goal look like this: if(all(arr, function(v){return v >= 0 && v <= 100})) { // do something } notice how now the condition is in the calling code. but it looks a bit… busy. so ES6 introduces this syntactic sugar: if(all(arr, (v) => v >= 0 && v <= 100)) { // do something }
Stepping past the goalposts • we can make all() an Array method if we rewrite it a little… Array.prototype.all = function(p) { for(var v ofthis) { if(!p(v)) { returnfalse } } return true } since we put this method in Array.prototype, all array objects inherit it. arr.all(v => v < 10) arr.all(v => typeof(v) === 'number')
It's a buncha arrays • document.querySelectorAll() gives you an array..ish thing. • arrays have a bunch of functional methods (see the links) • let's try these on the main course page: document.querySelectorAll('td') .forEach(v =>v.classList.add('canceled')) we can do something with every item with the forEach method. var topics = Array.from(document.querySelectorAll('td')) .map(v =>v.innerText) .filter(v =>v.includes('\n')) .map(v =>v.split('\n',2)[1])