Categories
programming languages

Semiotics of functional programming

In contrast to the usual imperative languages (e.g., C, Fortran, and Ada), in which variables represent cells in memory that can be modified using the assignment operator = (or  :=), functional languages view the use of the = operator as an expression of an equation. For example, if a functional program contains the declaration let x = f(y) then this would introduce the name x and assert that the equation x = f(y) is true. There is no notion of a memory cell, and certainly no notion that somehow later in the program x might change (so that the equation would become false) –  Goldberg, Functional Programming Languages, AMC Computing Surveys, March 1996.

Here’s a common mathematical expression

\(y = \Sigma_{x=1}^{x=10}x\)

The value of “x” changes from 1 to 10. Here’s part of the description from the great text by Aleksandrov, Kolmmogrov, and Lavrent’ev survey of mathematics chapter on Approximate Calculation of Roots.

\( \gamma_1 = – \frac{(b-a)fa(a)}{f(b)-f(a) +a }.\)
Taking this number for the new b in cases I and II and for the new a in cases II and IV we find …

This “new b” is not the same as the old b. And it’s not just in Soviet era Rusian math texts that we find such heretical material. Even in Abstract Algebra texts, we can find texts where “Let x be an element of the group G”  later is contradicted by “Let x be an element of the ring R” or, worse, where “x = 0” is later contradicted by “x ≠  0” .  Here’s more Functional Programming Doctrine:

As in mathematics, a function is a single-valued relation such that, given the same argument(s), it will return the same result. This is certainly not the case in the imperative programs.

Are functions single valued relations in mathematics? I guess, if we consider sets, vectors, and matrices and other collections to be single values. But given the same arguments, do they always return the same result? Not really:  f(x) = mx+b depends on the parameters “m” and “b” as well as on the argument “x”.   Consider the C function “f” defined by:

int f(int x){ static int b = 0; return x+ (b++); }

So ” x = f(1)+f(1)” is definitely not equal to “2*f(1)”  (it is equal to 3 )*. You could look at this as: “C is a terrible construct of math illiterates who probably didn’t even know how to spell monod”,  or you could see it as:  parameter b changes between invocations of “f” . In fact, you could look at the original crime in FORTRAN where “x = 2” was introduced as a statement and think: this is a rational convention in response to both the absence of subscripts on teletype machines and the inability of computers to understand what “…” means in  expressions like \(x_1 =2; x_{2} = x_1^2, …. x_n^n \) .   Or consider a recursive function

\[ f(x) = \begin{cases}1 &\mbox{if }x\leq 0\\
x* f(x-1) &\mbox{otherwise}
\end{cases} \]

If we calculate this for \(f(2)\), we get \(x =2\) and then \(x = 1\) and then \(x = 0\). Which is it? The answer is that “x” takes on different values as the calculation changes state!

The differences between (a) axiomatic (declarative) definitions and (b) algorithmic definitions and (c) non-mathematical definitions, are not properly acknowledged in much of the functional programming literature.  Calculations involve state change – of something. For most of the 20th century a “computer” was a person who calculated (computed).  Like Katherine Johnson, Dorothy Vaughan,  and Mary Jackson at NASA  they carried out engineering and science (and cryptography) calculations before digital computers were widely available. Imagine such a human computer using  Euler’s method. The “state of the computer” (the person doing the calculation) changes during the calculation as she iterates through (and possibly writes down intermediate results on paper). Similarly, electronic computers change state as they compute. Nothing to be afraid of here.

Not that the FP critique of imperative programming is all wrong.  Functions that only modify their return value are often much easier to understand and validate and,  too much programming still makes unstructured modifications to state – analogous to the old spaghetti code with unstructured control. New methods for clarifying what state can be changed by code sections and for facilitating modular decomposition of state would be useful.  Fetishizing an axiomatic approach to function definition as “mathematical” seems less so.

See also Computer Science as a Scholarly discipline.

FOOTNOTES

* I hope.

 

 

 

Categories
academics

Computer Science as a scholarly discipline.

Google Scholar tells me that “Why Functional Programming Matters” was published in 1989 and has been cited over 1000 times. Here’s a quote.

 Recall that a complete functional program is just a function from its input to its output. If f and g are such programs, then (g. f ) is a program that, when applied to its input, computes

g(f input)

The program f computes its output, which is used as the input to program g. This might be implemented conventionally by storing the output from f in a temporary file. The problem with this is that the temporary file might occupy so much memory that it is impractical to glue the programs together in this way. Functional languages provide a solution to this problem. The two programs f and g are run together in strict synchronization. Program f is started only when g tries to read some input, and runs only for long enough to deliver the output g is trying to read. Then f is suspended and g is run until it tries to read another input. As an added bonus, if g terminates without reading all of f ’s output, then f is aborted. Program f can even be a nonterminating program, producing an infinite amount of output, since it will be terminated forcibly as soon as g is finished. This allows termination conditions to be separated from loop bodies — a powerful modularization. Since this method of evaluation runs f as little as possible, it is called “lazy evaluation”. It makes it practical to modularize a program as a generator that constructs a large number of possible answers, and a selector that chooses the appropriate one.

From Dennis Ritchie’s 1972  UNIX paper:

An extension of the standard I/O notion is used to direct output from one command to the input of another. A sequence of commands separated by vertical bars causes the Shell to execute all the commands simultaneously and to arrange that the standard output of each command be delivered to the standard input of the next command in the sequence. Thus in the command line

ls | pr –2 | opr

ls lists the names of the files in the current directory; its output is passed to pr, which paginates its input with dated headings. The argument “–2” means double column. Likewise the output from pr is input to opr. This command spools its input onto a file for off-line printing

Back to “Why functional programming matters”

We have described lazy evaluation in the context of functional languages, but surely so useful a feature should be added to nonfunctional languages — or should it? Can lazy evaluation and side-effects coexist? Unfortunately, they cannot: Adding lazy evaluation to an imperative notation is not actually impossible, but the combination would make the programmer’s life harder, rather than easier. Because lazy evaluation’s power depends on the programmer giving up any direct control over the order in which the parts of a program are executed, it would make programming with side effects rather difficult, because predicting in what order —or even whether— they might take place would require knowing a lot about the context in which they are embedded. Such global interdependence would defeat the very modularity that —in functional languages— lazy evaluation is designed to enhance.

Oh.  See also: Semiotics of Functional Programming. 

 

 

Categories
Uncategorized

Current reading

img_20161121_152216238
Wadler’s influential “monads” paper for Haskell. It seems like a classic case of making something simple sound profound and mysterious.  And companion paper by Hughes on “why functional programming matters” . See also some comments above.

McCarthy’s original LISP paper.  Just terrible. He made a serious error picking Lambda calculus as a base notation.

A problem FSMLabs detected with GPS on London LD4 datacenter has been fixed. 

Dennis Ritchie and Albert Meyer on classification of recursive functions. I wish I could find a full copy of this.

The SEC Consolidated Audit is pushing clock sync requirements, but needs improvement.

The most successful functional language – Mathematica.

A critique of Haskell

A Haskell project at Facebook.

Some real engineering: the gcc optimizers.

Categories as algebra: An essential ingredient in the theory of monoids (via @joelvanderwerf )

Flash file system.