FP
- Appeared in:
- 1977
- Influenced:
- Paradigm:
- Typing discipline:
- File extensions:
- .fp
- Versions and implementations (Collapse all | Expand all):
FP (“Functional Programming”) is an algebraic programming language.
FP was invented by John Backus and presented in 1977 in a paper called “Can Programming Be Liberated from the von Neumann style? A Functional Style and its Algebra of Programs”. The language description given in this paper is the de facto standard of the language.
FP was designed as a model of language to support function-level programming style. It was intended to be more of a math model than of an actual language, and so it was. It is a canonical example of a language implementing function-level programming paradigm, but it has only a few implementations which differ quite a lot, and none of them is used in real-life development. However, the concept of FP had strong influence on development of other functional languages.
Most implementations use essentially different language syntax. The following description uses language notation taken from Interactive FP implementation.
As any function-level programming language, FP consists of three groups of entities:
1. atoms. FP uses the following types of atoms:
- scalar values. FP is designed to process numerical (both integer and floating-point) and logical (denoted as T and F) data. Some implementations, like Furry Paws, extend the language to allow processing strings as sequences of character codes.
-
sequences. A sequence is defined as
<x1, ..., xn>, where xi are another atoms. Note that atoms of different types can be intermixed in one sequence, so<1 <2 5.0> T>is a valid sequence. -
undefined value. This is the
undefinedused in definition of strict and non-strict paradigms: an atom which has no specific value, either because it has not been evaluated yet or because its evaluation has ended in an error. FP is strict language: all its functions and sequences are undefined-preserving, i.e., if function argument or one of elements in sequence isundefined, the return of the function or the sequence itself isundefinedas well.
As any function-level language, FP allows the use of atoms only as input and output values of the program. If program logic requires using a constant, a corresponding constant-value function is used.
2. functions can be primitive or user-defined. FP functions always take one atom as argument, which is written as f:x. The list of primitive functions includes:
-
identity:
id:xevaluates tox. -
constant-value:
%x:yevaluates toxfor any value ofy(some authors consider % to be a functional form, but it doesn’t have a function-type argument). -
math +,-,*,/:
+:<x y>evaluates tox+y, if x and y are scalar values. -
selector:
i:<x1 ... xn>evaluates toxi, if i is between 1 and n, inclusive. -
comparison =,>,<:
=:<x y>evaluates to T, if x=y, and to F otherwise. - a variety of vector and matrix functions, like concatenate, append, rotate, transpose etc.
-
user-defined functions have the following syntax:
{ functionName ( function code ) }. After a function is defined, it can be called in a same way as primitive functions are.
FP is typesafe: the function is evaluated only if its arguments are of correct types.
3. functional forms can not be user-defined. Unlike functions, forms can have multiple arguments. The list of standard forms includes:
-
construction:
[f1, ..., fn]:xevaluates to<f1:x ... fn:x>. -
composition:
f @ g:xevaluates tof:(g:x). -
conditional choice is written as
( condition -> trueChoice ; falseChoice )and applies to a value x using the following rules: first,condition:xis evaluated; if it results in T value,trueChoice:xis evaluated and returned, otherwisefalseChoice:xis returned. All three arguments of conditional are functions. -
apply-to-all:
@f:<x1 ... xn>evaluates to<f:x1 ... f:xn>. -
right insert:
!f:<x1 x2 ... xn>evaluates tof:<x1 !f:<x2 ... xn>>and is applied recursively;
!f:<x>evaluates tox(left insert is defined in a similar way).
Elements of syntax:
| Inline comments | % |
|---|
Examples:
Factorial:
Example for versions Interactive FPThis example defines four functions — two of necessity, and two for readability. All of them accept scalar values for input; seq returns a sequence of scalars, and the other three return individual scalars.
-
zerochecks whether its argument is equal to zero; -
decdecrements its argument; -
seqreturns<0>if its argumentxis equal to zero, andseq, applied to(x-1), withxappended to right otherwise (if we unwind this recursive definition, we’ll get simply the sequence of values<0 1 ... x>). -
factorialreturns 1 if its argumentxis equal to zero, andfactorial, applied to(x-1), multiplied byxotherwise.
The last line of the example applies factorial to each element of sequence, obtained by applying seq to 16. Note that all math operations produce floating point values, so the actual output will look like this:
< 1 1.0 2.0 6.0 24.0 120.0 720.0 5040.0 40320.0 362880.0 3628800.0 3.99168E7 4.790016E8 6.2270208E9 8.7178289E10 1.30767428E12 2.09227885E13 >
{ zero ( = @ [id, %0] ) }
{ dec ( - @ [id, %1] ) }
{ seq ( zero -> %<0> ; apndr @ [ seq @ dec , id ] ) }
{ factorial ( zero -> %1 ; * @ [id, factorial @ dec ] ) }
&factorial @ seq:16
Fibonacci numbers:
Example for versions Interactive FPThis example works in a same way as the factorial one, but without readability functions added.
{ seq ( = @ [id, %1] -> %<1> ; concat @ [ seq @ - @ [id, %1] , [id] ] ) }
{ fibonacci ( < @ [id, %3] -> %1 ; + @ [ fibonacci @ - @ [id, %1], fibonacci @ - @ [id, %2] ] ) }
&fibonacci @ seq:16
Hello, World!:
Example for versions Furry Paws~x is constant-value function (denoted with % in Interactive FP).
emit is a function which writes its argument to stdout.
main is a function which is the first to be invoked when the program is executed.
main = emit.(return ~"Hello, World!\n")
Factorial:
Example for versions Furry PawsThis example works in exactly the same way as the one in Interactive FP, except for that it doesn’t define zero function, since it’s built-in. Note that here all operations are done within integer data type, and 13! overflows it, so the program can be called only to print factorials up to 12!. show is another way to output data.
dec = sub.[id, ~1]
seq = zero -> [id] ; cat.[seq.dec, [id]]
factorial = zero -> ~1 ; mul.[id, factorial.dec]
main = show.(return @factorial.(seq.~12))
Fibonacci numbers:
Example for versions Furry PawsThis example works exactly like the one for Interactive FP.
one = eq.[id, ~1]
dec = sub.[id, ~1]
seq = one -> [~1] ; cat.[seq.dec, [id]]
fibonacci = lt.[id, ~3] -> ~1 ; add.[fibonacci.sub.[id, ~1], fibonacci.sub.[id, ~2]]
main = show.(return @fibonacci.(seq.~16))
Comments
]]>blog comments powered by Disqus
]]>