A place to cache linked articles (think custom and personal wayback machine)
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

5 роки тому
1234567
  1. title: The Two Pillars of JavaScript - Pt 2: Functional Programming
  2. url: https://medium.com/javascript-scene/the-two-pillars-of-javascript-pt-2-functional-programming-a63aa53a41a4
  3. hash_url: 867d86a67d14581fe6e57e0b82d9f146
  4. <p name="0c25" id="0c25" class="graf--p graf--first">In the very beginnings of the computing revolution, decades before the invention of the microprocessor, a man named <strong class="markup--strong markup--p-strong">Alonzo Church</strong> did groundbreaking work in theoretical computer science. You may have heard of his student and collaborator, <strong class="markup--strong markup--p-strong">Alan Turing</strong>. Together, they created a theory of computable functions called the <strong class="markup--strong markup--p-strong">Church-Turing Thesis</strong>, which described the nature of computable functions.</p><p name="8024" id="8024" class="graf--p">Two foundational models of computation emerged from that work. The famous <strong class="markup--strong markup--p-strong">turing machine</strong>, and <strong class="markup--strong markup--p-strong">lambda calculus</strong>.</p><p name="d6ac" id="d6ac" class="graf--p">Today, the turing machine is frequently cited as the baseline of requirements for a modern programming language. A language or processor / VM instruction set is said to be <strong class="markup--strong markup--p-strong">turing complete</strong> if it can be used to simulate a universal turing machine. The first famous example of a turing-complete system was lambda calculus, described by Alonzo Church in 1936.</p><p name="35bf" id="35bf" class="graf--p">Lambda calculus went on to inspire one of the first high-level programming languages, and the second-oldest high-level language in common use today: Lisp.</p><p name="4f4d" id="4f4d" class="graf--p">Lisp was (and remains) extremely influential and popular in academic circles, but it has also been very popular in productivity applications, particularly those that work on <strong class="markup--strong markup--p-strong">continuous data</strong> such as scalable vector graphics. Lisp was originally specified in 1958, and it’s still often embedded in many complex applications. Notably, almost all popular CAD applications support AutoLISP, a dialect of Lisp used in AutoCAD, which (including its many specialized derivatives) is still the most widely used CAD application in the world.</p><blockquote name="44c4" id="44c4" class="graf--blockquote">Continuous data: Data that must be measured rather than counted, and could take any value within a range. Contrast with discrete data, which can be counted and accurately indexed. All values come from a specific set of valid values. For instance, the frequencies that can be produced by a violin must be represented by continuous data, because the string can be stopped at any point along the fingerboard. The frequencies that can be produced by a piano are discrete, because each string is tuned to a specific pitch and can’t be stopped at different points depending on the performer’s will. There are usually 88 notes on a piano keyboard. It’s impossible to count the number of notes that could be produced by a violin player, and violin players frequently take advantage of that by sliding the pitch up or down between different notes.</blockquote><p name="18ed" id="18ed" class="graf--p">Lisp and its derivatives birthed an entire family of <strong class="markup--strong markup--p-strong">functional programming languages</strong> which includes Curry, Haskell, Erlang, Clojure, ML, OCaml, etc…</p><p name="bacb" id="bacb" class="graf--p">As popular as many of those languages are, JavaScript has exposed a whole new generation of programmers to functional programming concepts.</p><p name="c0cc" id="c0cc" class="graf--p">Functional programming is a natural fit for JavaScript, because JavaScript offers a few important features: First-class functions, closures, and simple lambda syntax.</p><p name="f937" id="f937" class="graf--p">JavaScript makes it easy to assign functions to variables, pass them into other functions, return functions from other functions, compose functions, and so on. JavaScript also offers immutable values for primitive types, and features that make it easy to return new objects and arrays rather than manipulate properties of those that are passed in as arguments.</p><p name="7c23" id="7c23" class="graf--p"><em class="markup--em markup--p-em">Why is all that important?</em></p><p name="a97b" id="a97b" class="graf--p">Functional programming glossaries contain a large number of large words, but at its core, the essence of FP is really very simple; programs are built mostly with a handful of very small, very reusable, very predictable <strong class="markup--strong markup--p-strong">pure functions.</strong></p><p name="3a35" id="3a35" class="graf--p">Pure functions have a few properties that make them extremely reusable and extremely useful for a variety of applications:</p><p name="d41a" id="d41a" class="graf--p"><strong class="markup--strong markup--p-strong">Idempotence:</strong> Given the same inputs, a pure function will always return the same output, regardless of the number of times the function is called. You may have heard this word used to describe HTTP GET requests. <strong class="markup--strong markup--p-strong">Idempotence is an important feature for building RESTful web services,</strong> but it also serves the very useful purpose of separating computation from dependency on both time and order of operations — <strong class="markup--strong markup--p-strong">extremely valuable for parallel &amp; distributed computation </strong>(think horizontal scaling).</p><p name="6aba" id="6aba" class="graf--p">Because of idempotence, pure functions are also a great fit when you need to operate on continuous data sets. For instance, automated fade-ins and fade-outs in video or audio. Typically they’re designed as linear or logarithmic curves independent of framerates or sample rates, and only applied at the last possible moment to produce discrete data values. In graphics, this is analogous to scalable vector images like SVG, fonts, and Adobe Illustrator files. Key frames or control points are laid out relative to each other or to a timeline, rather than keyed to fixed pixels, frames, or samples.</p><p name="a412" id="a412" class="graf--p">Because idempotent functions don’t have any dependency on time or sample resolution, it’s possible to treat continuous data as unbounded (virtually infinite) data streams, which allows free scaling of data across time, (sampling rates), pixel resolution, audio volume, and so on.</p><p name="4d99" id="4d99" class="graf--p"><strong class="markup--strong markup--p-strong">Free from Side-effects:</strong> Pure functions can be safely applied with no side-effects, meaning that they do not mutate any shared state or mutable arguments, and other than their return value, they don’t produce any observable output, including thrown exceptions, triggered events, I/O devices, network, console, display, logs, etc...</p><p name="5e95" id="5e95" class="graf--p">Because of the lack of shared state and side-effects, pure functions are much less likely to conflict with each other or cause bugs in unrelated parts of the program.</p><p name="5599" id="5599" class="graf--p">In other words, for the OOP coding audience, <strong class="markup--strong markup--p-strong">pure functions produce stronger guarantees of encapsulation than objects without function purity,</strong> and those guarantees provide many of the same benefits as encapsulation in OOP: The ability to change implementation without impacting the rest of the program, a self-documenting public interface (the function signature), independence from outside code, the ability to move code around freely between files, modules, projects, and so on.</p><p name="781a" id="781a" class="graf--p">Function purity is FP’s answer to the gorilla/banana problem from OOP:</p><blockquote name="5219" id="5219" class="graf--blockquote graf--startsWithDoubleQuote">“The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.” ~ Joe Armstrong</blockquote><p name="a100" id="a100" class="graf--p">Obviously, most programs need to produce output, so complex programs usually can’t be composed using <strong class="markup--strong markup--p-strong">only </strong>pure functions, but wherever it’s practical, it’s a good idea to make your functions pure.</p><p name="f3ae" id="f3ae" class="graf--p graf--empty"><br/></p><h4 name="a1a8" id="a1a8" class="graf--h4">Working in FP</h4><p name="8d49" id="8d49" class="graf--p graf--empty"><br/></p><p name="05f8" id="05f8" class="graf--p">FP provides several kinds of functions that are extremely reusable. Various implementations will have a different set using different names. This list is mostly pulled from Haskell documentation. Haskell is one of the more popular functional languages, but you’ll find functions similar to these in several popular JavaScript libraries:</p><p name="f43d" id="f43d" class="graf--p"><strong class="markup--strong markup--p-strong">List utilities:</strong></p><ul class="postList"><li name="e656" id="e656" class="graf--li">head() — get first element</li><li name="dc8a" id="dc8a" class="graf--li">tail() — get all but first elements</li><li name="23be" id="23be" class="graf--li">last() — get last element</li><li name="3d8a" id="3d8a" class="graf--li">length() — count of elements</li></ul><p name="8663" id="8663" class="graf--p"><strong class="markup--strong markup--p-strong">Predicates / comparators (test an element, return boolean)</strong></p><ul class="postList"><li name="0347" id="0347" class="graf--li">equal()</li><li name="77d4" id="77d4" class="graf--li">greaterThan()</li><li name="770e" id="770e" class="graf--li">lessThan()</li></ul><p name="0adc" id="0adc" class="graf--p"><strong class="markup--strong markup--p-strong">List transformations:</strong></p><ul class="postList"><li name="d849" id="d849" class="graf--li">map() ([x]) -&gt; [y] take list x and apply a transformation to each element in that list, return new list y</li><li name="9c6e" id="9c6e" class="graf--li">reverse() ([1, 2, 3]) -&gt; [3, 2, 1]</li></ul><p name="a195" id="a195" class="graf--p"><strong class="markup--strong markup--p-strong">List searches:</strong></p><ul class="postList"><li name="903d" id="903d" class="graf--li">find() ([x]) -&gt; x take list x and return first element that matches a predicate</li><li name="a674" id="a674" class="graf--li">filter() ([x]) -&gt; [y] take list x and return all items matching predicate</li></ul><p name="1c1b" id="1c1b" class="graf--p"><strong class="markup--strong markup--p-strong">List Reducers / folds:</strong></p><ul class="postList"><li name="7922" id="7922" class="graf--li">reduce() — ([x], function[, accumulator]) -&gt; apply function to each element and accumulate the results as a single value</li><li name="d780" id="d780" class="graf--li">any() — true if any values match predicate</li><li name="331b" id="331b" class="graf--li">all() — true if all values match predicate</li><li name="b387" id="b387" class="graf--li">sum() — total of all values</li><li name="2ee0" id="2ee0" class="graf--li">product() — product of all values</li><li name="9c64" id="9c64" class="graf--li">maximum() — highest value</li><li name="571a" id="571a" class="graf--li">minimum() — lowest value</li><li name="fc0f" id="fc0f" class="graf--li">concat() — take a list of lists and return a single, concatenated list in list order</li><li name="b475" id="b475" class="graf--li">merge() — take a list of lists and return a single, merged list in element order</li></ul><p name="0441" id="0441" class="graf--p"><strong class="markup--strong markup--p-strong">Iterators / Generators / Collectors (infinite lists)</strong></p><ul class="postList"><li name="1528" id="1528" class="graf--li">sample() — return current value of continuous input source (temperature, form input, toggle switch state, etc…)</li><li name="302e" id="302e" class="graf--li">repeat() — (1) -&gt; [1, 1, 1, 1, 1, 1,…]</li><li name="dd71" id="dd71" class="graf--li">cycle() / loop() — When the end of the list is reached, wrap around to the beginning again.</li></ul><p name="8646" id="8646" class="graf--p">Some of these common utility extras got added to JavaScript with the ECMAScript 5 Array extras. e.g.:</p><pre name="959d" id="959d" class="graf--pre">// Using ES6 syntax. () =&gt; means function () {}<br/>var foo = [1, 2, 3, 4, 5];<br/>var bar = foo.map( (n) =&gt; n + 1 ); // [2, 3, 4, 5, 6]<br/>var baz = bar.filter( (n) =&gt; n &gt;=3 &amp;&amp; n &lt;=5); // [3,4,5]<br/>var bif = baz.reduce( (n, el) =&gt; n += el); // 12</pre><p name="dd77" id="dd77" class="graf--p graf--empty"><br/></p><h4 name="2ad2" id="2ad2" class="graf--h4">Lists as a Generic Interface</h4><p name="2d63" id="2d63" class="graf--p graf--empty"><br/></p><p name="5615" id="5615" class="graf--p">You might notice that most of the functions above are utilities for managing or reasoning about <strong class="markup--strong markup--p-strong">lists</strong>. Once you start doing a lot of functional programming, you might start to see virtually everything as a <strong class="markup--strong markup--p-strong">list</strong>, an <strong class="markup--strong markup--p-strong">element</strong> of a list, a <strong class="markup--strong markup--p-strong">predicate</strong> used to test list values, or a <strong class="markup--strong markup--p-strong">transformation</strong> based on list values. That thinking lays the foundation for extremely reusable code.</p><p name="f4f1" id="f4f1" class="graf--p"><strong class="markup--strong markup--p-strong">Generics</strong> are functions that are capable of working on a range of different data types. In JavaScript, many functions that operate on collections are generic. For example, you can use the same function on both strings and arrays, because a string can be treated as an array of characters.</p><p name="be52" id="be52" class="graf--p">The process of changing a function that only works with a single type to one that works with many types is called <strong class="markup--strong markup--p-strong">lifting</strong>.</p><p name="9de2" id="9de2" class="graf--p">The key to all these functions working on every type of data you feed to them is that data is processed in lists which <strong class="markup--strong markup--p-strong">all share the same interface</strong>. I discussed lifting a bit towards the end of my Fluent 2014 talk, “Static Types are Overrated” (see below).</p><p name="edc5" id="edc5" class="graf--p graf--empty"><br/></p><h4 name="686b" id="686b" class="graf--h4">How to Stop Micromanaging Everything</h4><p name="017f" id="017f" class="graf--p graf--empty"><br/></p><p name="9900" id="9900" class="graf--p">In OO and imperative programming, we micromanage everything. We micromanage state, iteration counters, the timing of what happens when using things like event emitters and callbacks. What If I told you that all of that work is completely unnecessary — that you could literally delete entire categories of code from your programs?</p><p name="07d6" id="07d6" class="graf--p">You may have heard of <strong class="markup--strong markup--p-strong">functional reactive programming</strong>. Here’s the gist: FRP uses functional utilites like map, filter, and reduce to create and process data flows which propogate changes through the system: hence, <strong class="markup--strong markup--p-strong">reactive</strong>. When input <em class="markup--em markup--p-em">x</em> changes, output <em class="markup--em markup--p-em">y</em> updates <em class="markup--em markup--p-em">automatically</em> in response.</p><p name="3f3e" id="3f3e" class="graf--p">In OO, you might set up some object (say, a form input), and turn that object into an event emitter, and set up an event listener that jumps through some hoops and maybe produces some output whenever the event is triggered.</p><p name="2aad" id="2aad" class="graf--p">In FRP, you instead specify data dependencies in a more declarative fashion, and most of the heavy lifting is offloaded to standard functional utilities so you don’t have to reinvent the wheel over and over again.</p><p name="f364" id="f364" class="graf--p">Imagine that <strong class="markup--strong markup--p-strong">every list is a stream</strong>: An array is a stream of values in element order. A form input can be a stream of values sampled with each change. A button is a stream of clicks.</p><blockquote name="5eb5" id="5eb5" class="graf--pullquote pullquote">A stream is just a list expressed over time.</blockquote><p name="b924" id="b924" class="graf--p">In Rx (reactive extensions) nomenclature, you create <strong class="markup--strong markup--p-strong">observable streams </strong>and then process those streams using a set of functional utilities like the ones described above.</p><p name="6b8b" id="6b8b" class="graf--p">Similar to Node streams, <strong class="markup--strong markup--p-strong">observables</strong> can feature optional shared <strong class="markup--strong markup--p-strong">backpressure</strong>. Like <strong class="markup--strong markup--p-strong">generators</strong>, your program can consume observable values at its own pace, as it becomes ready to handle them.</p><p name="27a6" id="27a6" class="graf--p">Imagine you want to watch all your social media feeds for a particular hash tag. You could collect a list of lists, merge them in the order they’re received, and then use any combination of the utility functions above to process them.</p><p name="be92" id="be92" class="graf--p">That might look something like this:</p><pre name="1634" id="1634" class="graf--pre">var messages = merge(twitter, fb, gplus, github)</pre><pre name="fe81" id="fe81" class="graf--pre">messages.map(normalize) // convert to single message format<br/> .filter(selectHashtag) // cherry pick messages that use the tag<br/> .pipe(process.stdout) // stream output to stdout</pre><p name="56bf" id="56bf" class="graf--p graf--empty"><br/></p><h4 name="dc94" id="dc94" class="graf--h4">Better Async</h4><p name="d765" id="d765" class="graf--p graf--empty"><br/></p><p name="1aed" id="1aed" class="graf--p">You may have heard of promises. A <strong class="markup--strong markup--p-strong">promise </strong>is an object that provides a standard interface for dealing with values that may or may not be available at the time the promise is used. In other words, a promise wraps a potential value that may be resolved in the future. Typically, a function call will return a promise that may resolve with some future value:</p><pre name="56f2" id="56f2" class="graf--pre">fetchFutureStockPrices().then(becomeAMillionaire);</pre><p name="d85f" id="d85f" class="graf--p">Well, it doesn’t work exactly like that, because `.then()` will only be called when the stock prices become available, so when `becomeAMillionaire` finally gets run, the “future” stock prices will be the present stock prices.</p><p name="dd2e" id="dd2e" class="graf--p">A promise is basically a stream that only emits a single value (or rejection). Observables can replace promises in your code and provide all of the standard functional utilities you may have grown accustomed to with libraries like Underscore or Lo-Dash.</p><p name="ed06" id="ed06" class="graf--p">Now would be a great time to learn more about functional programming, the benefits of function purity, lazy evaluation, and a lot more. I promise you’re going to hear a lot more about these topics over the next few years.</p><p name="8bf3" id="8bf3" class="graf--p">Here we are, coming up on 2015, returning to computer science roots planted in the 1930's so that we can more easily manage the software of future.</p><h4 name="a48a" id="a48a" class="graf--h4">Higher Order Learning</h4><p name="58e2" id="58e2" class="graf--p graf--empty"><br/></p><p name="0654" id="0654" class="graf--p">I really loved this talk by Jafar Husain, Technical Lead at Netflix. It’s called, “Asynchronous Programming at Netflix” and it was delivered at <a target="_blank" href="http://atscaleconference.com/" data-href="http://atscaleconference.com/" class="markup--anchor markup--p-anchor" rel="nofollow">@Scale 2014</a>.</p><figure name="9583" id="9583" class="graf--figure graf--iframe"><p class="iframeContainer"/><figcaption class="imageCaption"><a target="_blank" href="https://www.youtube.com/watch?v=gawmdhCNy-A" data-href="https://www.youtube.com/watch?v=gawmdhCNy-A" class="markup--anchor markup--figure-anchor" rel="nofollow">https://www.youtube.com/watch?v=gawmdhCNy-A</a></figcaption></figure><p name="6f66" id="6f66" class="graf--p">James Coglan gave a good talk that touches on some key topics such as the roles of promises and laziness:</p><figure name="9107" id="9107" class="graf--figure graf--iframe graf--last"><p class="iframeContainer"/></figure>
  5. <p name="1bd9" id="1bd9" class="graf--p graf--first">If you’re ready to take FRP for a spin, check out the <a target="_blank" href="https://github.com/Reactive-Extensions/RxJS" data-href="https://github.com/Reactive-Extensions/RxJS" class="markup--anchor markup--p-anchor" rel="nofollow">Reactive Extensions for JavaScript</a>, <a target="_blank" href="http://www.reactivemanifesto.org/" data-href="http://www.reactivemanifesto.org/" class="markup--anchor markup--p-anchor" rel="nofollow">The Reactive Manifesto</a>, and work through these <a target="_blank" href="http://jhusain.github.io/learnrx/" data-href="http://jhusain.github.io/learnrx/" class="markup--anchor markup--p-anchor" rel="nofollow">interactive lessons</a>.</p><p name="97ab" id="97ab" class="graf--p">For node-centric streams, check out <a target="_blank" href="http://caolanmcmahon.com/posts/how_i_want_to_write_node_stream_all_the_things_new/" data-href="http://caolanmcmahon.com/posts/how_i_want_to_write_node_stream_all_the_things_new/" class="markup--anchor markup--p-anchor" rel="nofollow">“How I Want to Write Node: Stream All the Things!”</a> and <a target="_blank" href="http://highlandjs.org/" data-href="http://highlandjs.org/" class="markup--anchor markup--p-anchor" rel="nofollow">Highland.js</a>.</p><p name="a4ba" id="a4ba" class="graf--p">For a much more detailed overview of concepts related to reactivity, see Kris Kowal’s excellent <a target="_blank" href="https://github.com/kriskowal/gtor" data-href="https://github.com/kriskowal/gtor" class="markup--anchor markup--p-anchor" rel="nofollow">“General Theory of Reactivity”</a> (aka gtor).</p><p name="026b" id="026b" class="graf--p">My talk from Fluent 2014 demonstrates lifting and discusses how dynamic or inferred types can actually be beneficial to functional programming because it makes it trivial to write generic functions.</p>