ted.neward@newardassociates.com | Blog: http://blogs.newardassociates.com | Github: tedneward | LinkedIn: tedneward
What is a programming language?
a formal language designed to translate ideas into machine instructions
What do programming languages do for us?
they provide "first-class concepts"
they provide a means for thinking about the problem
they provide an abstraction principle
What is the abstraction principle?
Pierce (2002), from "Types and Programming Languages":
"Each significant piece of functionality in a program should be implemented in just one place in the source code. Where similar functions are carried out by distinct pieces of code, it is generally beneficial to combine them into one by abstracting out the varying parts."
Cole/Morrison (1982), from "An introduction to programming with S-algol":
"a basic dictum that aims to reduce duplication of information in a program (usually with emphasis on code duplication) whenever practical by making use of abstractions provided by the programming language or software libraries."
Pearce (1998), "Programming and Meta-Programming in Scheme":
"Structure and function should be independent"
In short:
like most languages, programming languages give us a framework--a set of abstractions--by which we can think about (and solve) problems
if the abstraction does not exist within the language, it is difficult (if not impossible) to embrace or use
In the beginning, God created objects....
Functional programming is a different way of thinking about modularizing applications
And, admittedly at times it is a different way of thinking that runs entirely contradictory to the way that object-oriented programmers think
immutable values over mutable variables
functions as first-class values
currying, partial-application of functions
expressions-not-statements
laziness/deferred execution
once bound, a binding remains constant throughout its lifetime
thus offers no opportunity for confusion/reassignment/etc
"values" are not "variables"
name/value binding is fixed once bound
A functional pseudocode example
let x = 0 // or sometimes "val" let y = 1 let z = x + y
think about common operations-if we could vary the actual operation itself as a parameter, how much work could be saved?
example: you need to iterate through a collection to...
... and each time you write it as a "for" loop, you're violating DRY
this enables the use of functions as "higher-order" functions
"take this function, and execute inside your context"
similar in some ways to a callback, but with clearer semantics
in a lot of ways, this is Inversion-of-Control all over again
Higher-order functions
let numbers = [1, 2, 3, 4, 5] let squares = numbers.map((num) -> num * num); // squares = [1, 4, 9, 16, 25]
In functional languages, we can build functions out of functions
This allows us to achieve reuse through the composition/combination of functional parts into larger functions
By doing so, we "build up" larger more complex functions
When combining several in a row using currying, this is also called "pipelining"
providing some of the parameters (but not all) to a function and capturing that as a function to be called
Partial application
let add x y = x + y let five = add 2 3 // = 5 let addBy2 = add 2 // = (anonymous fn) = 2 + y let six = addBy2 addBy2 2 // = 6
it turns out (thank you Alonzo Church!) that all functions can be reduced to functions taking one parameter and either yielding a result or another function
this permits easy "pipelining" and composition of functions in a highly reusable manner (at the micro level)
this is an outgrowth of the functions-as-first-class-citizens idea: if functions yield values, what is the practical difference between a keyword and a function?
even C++ tried to make user-defined elements look and feel like built-in constructs and vice versa
if we're really good about this, developers can create new "language" primitives and nobody will know the difference
object-oriented laziness has nothing on functional laziness
don't compute anything until absolutely necessary (but make sure to maintain the dependency graph so everything is there when needed)
laziness is highly encouraged/permissible in pure FP
just to be fair, laziness is highly desirable inside the process, not so across processes unless carefully managed
lots of things can be seen as sequences
characters in a string
fields in a record
records in a database
files in a directory
algorithmic calculations (factorial, fibonacci, ...)
lines in a file
user interactions
sequences and collections have a deep relationship
in many ways, this is the gateway to FP ideas/concepts
strongly-typed, type-inferenced
recursion
tuples, lists
pattern-matching
Strongly-typed
the dynamic language community will have you believe that it's better to write unit tests by hand than to have a system that can do common-sense checking for you
Type-inferenced
why do I have to be explicit to the language/compiler, when it can figure out what I'm trying to do and when?
Recursion
immutable values doesn't mean no state changes
instead, hold state on the stack, not in mutable memory
Tuples, lists
"bundles" of data in different directions
tuples give developers a "lightweight" object that needn't be named or otherwise formalized
Pattern-matching
switch/case is to pattern-matching as my kid's soccer team is to Arsenal or Manchester United
pattern-matching also encourages "destructuring" of data when necessary/desired
pattern-matching can operate off of collections of values
Abstractions
Parsing, for example, is made easier because the functional approach better matches what parsers do
Transaction Scripts (Fowler, Patterns of Enterprise Application Architecture) are ideally highly functional in nature
How many tortured object designs must we build before we acknowledge that objects don't fit everything we build?
Continuations
instead of wiring steps together explicitly, do it implicitly by passing in the next "thing" to do as a function
Concurrency
instead of locking explicitly, allow the underlying language library or runtime to manage the physical details of the parallelization, or (better yet) avoid the need entirely
Functional programming is not going to replace object-orientation
objects didn't replace procedural programming, but built on top of it and incorporated it
most new FP languages are functional/object hybrids, not pure FP languages
The best functional usage, then, will supplement your objects, and vice versa
Functional programming represents a new tool in your toolbox, not wholesale rejection of prior art