I am dealing with the concept of functional programming for a while now and find it quite interesting, fascinating and exciting. Especially the idea of pure functions is awesome, in various terms.
But there is one thing I do not get: How to deal with side-effects when restricting yourself to pure functions.
E.g., if I want to calculate the sum of two numbers, I can write a pure function (in JavaScript):
var add = function (first, second) {
return first + second;
};
No problem at all. But what if I want to print the result to the console? The task of "printing something to the console" is not pure by definition - but how could / should I deal with this in a pure functional programming language?
There are a few approaches to this. One thing you will just have to accept is that at some point, there exists a magical impure machine that takes pure expressions and makes them impure by interacting with the environment. You are not supposed to ask questions about this magical machine.
There are two approaches I can think of off the top of my head. There exists at least a third one I have forgotten about.
I/O Streams
The approach that is easiest to understand could be streaming I/O. Your main function takes one argument: a stream of things that have happened on the system – this includes keypresses, files on the file system, and so on. Your main function also returns one thing: a stream of things that you want to happen on the system.
Streams are like lists, mind you, only you can build them one element at a time and the recipient will receive the element as soon as you have built it. Your pure program reads from such a stream, and appends to its own stream when it wants the system to do something.
The glue that makes all of this work is a magical machine that sits outside of your program, reads from the "request" stream and puts stuff into the "answers" stream. While your program is pure, this magical machine is not.
The output stream could look like this:
[print('Hello, world! What is your name?'), input(), create_file('G:\testfile'), create_file('C:\testfile'), write_file(filehandle, 'John')]
and the corresponding input stream would be
['John', IOException('There is no drive G:, could not create file!'), filehandle]
See how the input in the out-stream resulted in 'John' appearing in the in-stream? That's the principle.
Monadic I/O
Monadic I/O is what Haskell does, and does really well. You can imagine this as building a giant tree of I/O commands with operators to glue them together, and then your main function returns this massive expression to a magical machine that sits outside of your program and executes the commands and performs the operations indicated. This magical machine is impure, while your expression-building program is pure.
You might want to imagine this command tree looking something like
main
|
+---- Cmd_Print('Hello, world! What is your name?')
+---- Cmd_WriteFile
|
+---- Cmd_Input
|
+---+ return validHandle(IOResult_attempt, IOResult_safe)
+ Cmd_StoreResult Cmd_CreateFile('G:\testfile') IOResult_attempt
+ Cmd_StoreResult Cmd_CreateFile('C:\testfile') IOResult_safe
The first thing it does is print a greeting. The next thing it does is that it wants to write a file. To be able to write to the file, it first needs to read from the input whatever it's supposed to write to the file. Then it is supposed to have a file handle to write to. It gets this from a function called validHandle that returns the valid handle of two alternatives. This way, you can mix what looks like impure code with what looks like pure code.
This "explanation" is bordering on asking questions about the magical machine you're not supposed to ask questions about, so I'm going to wrap this up with a few pieces of wisdom.
Real monadic I/O looks nowhere near my example here. My example is one of the possible explanations for how monadic I/O can look like "under the hood" without breaking purity.
Do not try to use my examples to understand how to work with pure I/O. How something works under the hood is something completely different to how you do things with it. If you had never seen a car before in your life, you wouldn't become a good driver by reading the blueprints for one either.
The reason I keep saying you're not supposed to ask questions about the magical machine that actually does stuff is that when programmers learn things, they tend to want to go poke at the machinery to try to figure it out. I don't recommend doing so for pure I/O. The machinery might not teach you anything about how to use different variants of I/O.
This is similar to how you don't learn Java by looking at the disassembled JVM bytecode.
Do learn to use monadic I/O and stream-based I/O. It's a cool experience and it's always good to have more tools under your toolbelt.
Haskell, a pure functional language, handles "impure" functions using "monads." A monad is basically a pattern that makes it easy to chain function calls with continuation passing. Conceptually, the print function in Haskell basically takes three parameters: the string to be printed, the state of the program, and the rest of the program. It calls the rest of the program while passing in a new state of the program where the string is on the screen. This way no state has been modified.
There are many in-depth explanations of how monads work because for some reason people think it's a concept that's difficult to grasp: it's not. You can find many by searching on the Internet, I think this is one that I like the most: http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html
I am dealing with the concept of functional programming for a while now [...] But there is one thing I do not get: How to deal with side-effects when restricting yourself to pure functions.
Claus Reinke posed a similar question when writing his thesis - from page 10 of 210:
How must interactions between a program and an external environment (consisting of, e.g., input/output-devices, file systems, ...) be described in a programming language that abstracts from the existence of an outside world?
For functional languages like Haskell which strive for the mathematical notion of a function, this brings up another question:
As mathematics also abstracts from the existence of an external environment (consisting of, e.g., input/output-devices, file systems, etc.):
In a preliminary sense, mathematics is abstract because it is studied using highly general and formal resources.
The Applicability of Mathematics (The Internet Encyclopedia of Philosophy).
then why would anyone try using mathematics to describe interactions with an external environment, namely those which are supported by a programming language?
It just seems counterintuitive...
At a time when "traditional programming languages" were almost always imperative:
During the 1960s, several researchers began work on proving things about programs. Efforts were made to prove that:
A program was correct.
Two programs with different code computed the same answers when given the same inputs.
One program was faster than another.
A given program would always terminate.
While these are abstract goals, they are all, really, the same as the practical goal of "getting the program debugged".
Several difficult problems emerged from this work. One was the problem of specification: before one can prove that a program is correct, one must specify the meaning of "correct", formally and unambiguously. Formal systems for specifying the meaning of a program were developed, and they looked suspiciously like programming languages.
The Anatomy of Programming Languages (page 353 of 600), Alice E. Fischer and Frances S. Grodzinsky.
(emphasis added.)
Claus Reinke makes a similar observation - from page 65 of 210:
The notation for interactive programs written in the monadic style is irritatingly close to the notation used in imperative languages.
But there is still a possibility of success:
Researchers began to analyze why it is often harder to prove things about programs written in traditional languages than it is to prove theorems about mathematics. Two aspects of traditional languages emerged as sources of trouble because they are very difficult to model in a mathematical system: mutability and sequencing.
The Anatomy of Programming Languages (same page.)
("Very difficult", but not "impossible" - and apparently less than practical.)
Perhaps the remaining issues will be resolved at some time during the 2260s 2060s, using an extended set of elementary mathematical concepts. Until then, we'll just have to make do with awkward I/O-centric types e.g:
IO is not denotative.
Conal Elliott.
Since IO has (sort of) been explained elsewhere, let's try something different - inspired by Haskell's FFI:
data FF a b -- abstract "tag" type
foreign import ccall "primArrFF" arrFF :: (a -> b) -> FF a b
foreign import ccall "primPipeFF" pipeFF :: FF a b -> FF b c -> FF a c
foreign import ccall "primBothFF" bothFF :: FF a b -> FF c d -> FF (a, c) (b, d)
foreign import ccall "primAltFF" altFF :: FF a b -> FF c d -> FF (Either a c) (Either b d)
foreign import ccall "primAppFF" appFF :: FF (FF a b, a) b
foreign import ccall "primTieFF" tieFF :: FF (a, c) (b, c) -> FF a b
⋮
foreign import ccall "primGetCharFF" getChar :: FF () Char
foreign import ccall "primPutCharFF" putChar :: FF Char ()
⋮
As for Main.main:
module Main(main) where
main :: FF () ()
⋮
...which can be expanded to:
module Main() where
foreign export ccall "FF_main" main :: FF () ()
⋮
(FF's instances for Arrow, et al are left as an exercise ;-)
So for now (2022 Jan) this how you can deal with side-effects when restricting yourself to ordinary Haskell functions:
Introduce an appropriate abstract type (FF a b) for entities with observable effects;
Introduce two sets of primitives - one set of combinators (arrFF, pipeFF, bothFF, altFF, appFF, tieFF, etc.) and one set of non-standard morphisms (getChar, putChar, etc);
You then define Main.main :: FF () () using ordinary Haskell functions and those FF primitives.
In this way, ordinary Haskell functions can remain free of side-effects - they don't actually "run" FF entities, but build them from other (usually smaller) ones. The only FF entity to be "run" is Main.main via its foreign export, which is called by the runtime system (usually implemented in an imperative language which allows side-effects).
Related
I am aware that declarative programming just passes the input and expects the output without stating the procedure how it is done. In functional programming, is a programming paradigm, which takes an input and returns an output. When I checked the Higher order functional programming, we pass a function to map/reduce, which does not reveal the procedure how it is done. So is higher order functional programming and declarative programming the same thing??
Short answer: No.
Wikipedia defines declarative programming as:
In computer science, declarative programming is a programming
paradigm - a style of building the structure and elements of computer
programs - that expresses the logic of a computation without describing
its control flow.
Or to state it a bit boldly: "Say what you want, not how you want it.".
This is thus in contrast with imperative programming languages where a program is seen as a set of instructions that are done one after another. The fact that map, etc. do not reveal the procedure does not make it declarative: one can use a lot of C libraries that are proprietary and do not allow you to inspect the source code. That however, does not mean that these are declarative.
The definition of functional programming on the other hand is:
In computer science, functional programming is a programming paradigm
- a style of building the structure and elements of computer programs - that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. It is a declarative
programming paradigm, which means programming is done with expressions
or declarations instead of statements.
Based on these definitions one could say that functional programming is a subset of declarative programming. In a practical sense however if we follow the strict definitions, no programming language nowadays is purely, and un-ambigously declarative or functional. One can however say that Haskell is more declarative than Java.
Declarative programming is usually considered to be "safer" since people tend to have trouble managing side-effects. A lot of programming errors are the result of not taking all side effects into account. On the other hand it is hard to
design a language that allows a programmer to describe what he wants without going into details on how to do it;
implement a compiler that will generate - based on such programs - an efficient implementation; and
some problems have inherent side effects. For instance if you work with a database, a network connection or a file system, then reading/writing to a file for instance is supposed to have side effects. One can of course decide not to make this part of the programming language (for instance many constraint programming languages do not allow these type of actions, and are a "sub language" in a larger system).
There have been several attempts to design such language. The most popular are - in my opinion - logic programming, functional programming, and constraint programming. Each has its merits and problems. We can also observe this declarative approach in for instance databases (like SQL) and text/XML processing (with XSLT, XPath, regular expressions,...) where one does not specify how a query is resolved, but simply specifies through for instance the regular expression what one is looking for.
Whether a programming language is however declarative, is a bit of a fuzzy discussion. Although programming languages, modeling languages and libraries like Haskell, Prolog, Gecode,... have definitely made programming more declarative, these are probably not declarative in the most strict sense. In the most strict sense, one should think that regardless how you write the logic, the compiler will always come up with the same result (although it might take a bit longer).
Say for instance we want to check whether a list is empty in Haskell. We can write this like:
is_empty1 :: [a] -> Bool
is_empty1 [] = True
is_empty1 (_:_) = False
We can however write it like this as well:
is_empty2 :: [a] -> Bool
is_empty2 l = length l == 0
Both should give the same result for the same queries. If we however give it an infinite list, is_empty1 (repeat 0) will return False whereas is_empty2 (repeat 0) will loop forever. So that means that we somehow still wrote some "control flow" into the program: we have defined - to some extent - how Haskell should evaluate this. Although lazy programming will result in the fact that a programmer does not really specify what should be evaluated first, there are still specifications how Haskell will evaluate this.
According to some people, this is the difference between programming and specifying. One of my professors once stated that according to him, the difference is that when you program something, you have somehow control about how something is evaluated, whereas when you specify something, you have no control. But again, this is only one of the many definitions.
Not entirely, functional programming emphasises more on what to compute rather than how to compute. However, there are patterns available in functional programming that are pretty much control flow patterns you would commonly associate with declarative programming, take for example the following control flow:
let continue = ref true in
while !continue do
...
if cond then continue := false
else
...
done
Looks familiar huh? Here you can see some declarative constructs but this time round we are in more control.
I'm trying to get my head around a core concept of functional langauges:
"A central concept in functional languages is that the result of a function is determined by its input, and only by its input. There are no side-effects!"
http://www.haskell.org/haskellwiki/Why_Haskell_matters#Functions_and_side-effects_in_functional_languages
My question is, if a function makes changes only within its local environment, and returns the result, how can it interact with a database or a file system? By definition, wouldn't that be accessing what is in effect a global variable or global state?
What is the most common pattern used to get around or address this?
Just because a functional language is functional (Maybe even completely pure like Haskell!), it doesn't mean that programs written in that language must be pure when ran.
Haskell's approach, for example, when dealing with side-effects, can be explained rather simply: Let the whole program itself be pure (meaning that functions always return the same values for the same arguments and don't have any side effect), but let the return value of the main function be an action that can be ran.
Trying to explain this with pseudocode, here is some program in an imperative, non-functional language:
main:
read contents of abc.txt into mystring
write contents of mystring to def.txt
The main procedure above is just that: a series of steps describing how to perform a series of actions.
Compare this to a purely functional language like Haskell. In functional languages, everything is an expression, including the main function. One can thus read the equivalent of the above program like this:
main = the reading of abc.txt into mystring followed by
the writing of mystring to def.txt
So, main is an expression that, when evaluated, will return an action describing what to do in order to execute the program. The actual execution of this action happens outside of the programmers world. And this is really how it works; the following is an actual Haskell program that can be compiled and ran:
main = readFile "abc.txt" >>= \ mystring ->
writeFile "def.txt" mystring
a >>= b can be said to mean "the action a followed by the result of a given to action b" in this situation, and the result of the operator is the combined actions a and b. The above program is of course not idiomatic Haskell; one can rewrite it as follows (removing the superfluous variable):
main = readFile "abc.txt" >>=
writeFile "def.txt"
...or, using syntactic sugar and the do-notation:
main = do
mystring <- readFile "abc.txt"
writeFile "def.txt" mystring
All of the above programs are not only equivalent, but they are identical as far as the compiler is concerned.
This is how files, database systems, and web servers can be written as purely functional programs: by threading action values through the program so that they are combined, and finally end up in the main function. This gives the programmer enormous control over the program, and is why purely functional programming languages are so appealing in some situations.
The most common pattern for dealing with side-effects and impurity in functional languages is:
be pragmatic, not a purist
provide built-ins that allow impure code and side-effects
use them as little as possible!
Examples:
Lisp/Scheme: set!
Clojure: refs, and using mutating methods on java objects
Scala: creating variables with var
ML: not sure of specifics, but Wikipedia says it allows some impurity
Haskell cheats a little bit -- its solution is that for functions that access the file system, or the database, the state of the entire universe at that instant, including the state of the filesystem/db, will be passed in to the function.(1) Thus, if you can replicate the state of the entire universe at that instant, then you can get the same results twice from such a function. Of course, you can't replicate the state of the entire universe at that instant, and so the functions return different values ...
But Haskell's solution, IMHO, is not the most common.
(1) Not sure of the specifics here. Thanks to CAMcCann for pointing out that this metaphor is overused and maybe not all that accurate.
Acessing a database is no different from other cases of input-output, such as print(17).
In eagerly evaluated languages, like LISP and ML the usual approach to effectful programming is just using side effects, like in most other programming languages.
In Haskell, the solution for the IO problem is using monads. For example, if you check HDBC, a haskell database library, you can see lots of functions there return IO actions.
Some languages, like Clean, use uniqueness-types to enforce the same kind of sequentiality Haskell does with monads but these languages are harder to find nowadays.
Since side-effects break referential transparency, don't they go against the point of functional languages?
There are two techniques that are used by purely functional programming languages to model side effects:
1) A world type that represents external state, where each value of that type is guaranteed by the type system to be used only once.
In a language that uses this approach the function print and read might have the types (string, world) -> world and world -> (string, world) respectively.
They might be used like this:
let main w =
let w1 = print ("What's your name?", w) in
let (name, w2) = read w1 in
let w3 = print ("Your name is " ^ name, w2) in
w3
But not like this:
let main w =
let w1 = print ("What's your name?", w) in
let (name, w2) = read w in
let w3 = print ("Your name is " ^ name, w2) in
w3
(because w is used twice)
All built-in functions with side-effects would take and return a world value. Since all functions with side-effects are either built-ins or call other functions with side-effects, this means that all functions with side-effects need to take and return a world.
This way it is not possible to call a function with side-effects twice with the same arguments and referential transparency is not violated.
2) An IO monad where all operations with side effects have to be executed inside that monad.
With this approach all operations with side effects would have type io something. For example print would be a function with type string -> io unit and read would have type io string.
The only way to access the value of performing operation would be to use the "monadic bind" operation (called >>= in haskell for example) with the IO operation as one argument and a function describing what to do with the result as the other operand.
The example from above would look like this with monadic IO:
let main =
(print "What's your name?") >>=
(lambda () -> read >>=
(lambda name -> print ("Your name is " ^ name)))
There are several options available to handle I/O in a functional language.
Don't be pure. Many functional languages aren't purely functional. It's more that they support
functional programming rather than enforcing it. This is by far the most common solution to the problem
of I/O in functional programming. (Examples: Lisp, Scheme, Standard ML, Erlang, etc.)
Stream transformation. Early Haskell I/O was done this way. Check my link below for details if you
want more information. (Hint: you probably don't.)
Continuation-passing I/O (the "world-passing" mentioned in other answers). In this one you pass a token
of data around with your I/O that acts as the necessary "different value" to keep referential integrity
alive. This is used by several ML dialects if memory serves.
The "continuation" or "world" thing above can be wrapped in various data types, the most (in)famous
being the use of monads in this role in Haskell. Note that this is, notionally, the same thing under
the covers, but the tedium of keeping track of "world"/"continuation" state variables is removed.
There's a research dissertation that exhaustively analyses these.
Functional I/O is an ongoing field of research and there are other languages which address this issue in interesting and mind-mangling ways. Hoare logic is put to use in some research languages. Others (like Mercury) use uniqueness typing. Still others (like Clean) use effect systems. Of these I have a very, very limited exposure to Mercury only, so I can't really comment on details. There's a paper that details Clean's I/O system in depth, however, if you're interested in that direction.
To the best of my understanding, if you want to have side effects in a functional language, you have to code them explicitly.
Since side-effects break referential transparency, don't they go against the point of functional languages?
It depends on the functional language:
Standard ML allows the liberal use of side-effects like most procedural languages e.g. Fortran, Algol, Pascal, C, etc.
Haskell restricts side-effects through the use of abstract data types like IO, ST and STM, which helps to preserve referential transparency.
Clean also restricts side-effects, but does this with its extended type system.
The functional language Coq uses - Gallina - provides no access to side-effects at all.
How do functional languages model side-effects?
One approach which isn't regularly mentioned relies on pseudo-data: individual single-use abstract values conveyed in an accessible structured value (commonly a tree), with the side effects only occuring when each abstract value is initially used. For more information, see F. Warren Burton's Nondeterminism with Referential Transparency in Functional Programming Language. An working example can also be found in GHC: its Unique name-supply type.
But if the extra parameters needed to make pseudo-data work is just too annoying, it is actually possible to usefully combine I/O and its observable effects with non-strict semantics...if you don't really need referential transparency.
monads are described as the haskell solution to deal with IO. I was wondering if there were other ways to deal with IO in pure functional language.
What alternatives are there to monads for I/O in a pure functional language?
I'm aware of two alternatives in the literature:
One is a so-called linear type system. The idea is that a value of linear type must be used exactly one time: you can't ignore it, and you can't use it twice. With this idea in mind, you give the state of the world an abstract type (e.g., World), and you make it linear. If I mark linear types with a star, then here are the types of some I/O operations:
getChar :: World* -> (Char, World*)
putChar :: Char -> World* -> World*
and so on. The compiler arranges to make sure you never copy the world, and then it can arrange to compile code that updates the world in place, which is safe because there is only one copy.
The uniqueness typing in the language Clean is based on linearity.
This system has a couple of advantages; in particular, it doesn't enforce the total ordering on events that monads do. It also tends to avoid the "IO sin bin" you see in Haskell where all effectful computations are tossed into the IO monad and they all get totally ordered whether you want total order or not.
The other system I'm aware of predates monads and Clean and is based on the idea that an interactive program is a function from a (possibly infinite) sequence of requests to a (possibly infinite) sequence of responses. This system, which was called "dialogs", was pure hell to program. Nobody misses it, and it had nothing in particular to recommend it. Its faults are enumerated nicely in the paper that introduced monadic I/O (Imperative Functional Programming) by Wadler and Peyton Jones. This paper also mentions an I/O system based on continuations which was introduced by the Yale Haskell group but which was short-lived.
Besides linear types, there's also effect system.
If by "pure" you mean "referentially transparent", that is, that an applied function is freely interchangeable with its evaluated result (and therefore that calling a function with the same arguments has the same result every time), any concept of stateful IO is pretty much excluded by definition.
There are two rough strategies that I'm aware of:
Let a function do IO, but make sure that it can never be called twice with the exact same arguments; this side-steps the issue by letting the functions be trivially "referentially transparent".
Treat the entire program as a single pure function taking "all input received" as an argument and returning "all output produced", with both represented by some form of lazy stream to allow interactivity.
There are a variety of ways to implement both approaches, as well as some degree of overlap--e.g., in the second case, functions operating on the I/O streams are unlikely to be called twice with the same part of the stream. Which way of looking at it makes more sense depends on what kind of support the language gives you.
In Haskell, IO is a type of monad that automatically threads sequential state through the code (similar to the functionally pure State monad), such that, conceptually, each call to an otherwise impure function gets a different value of the implicit "state of the outside world".
The other popular approach I'm aware of uses something like linear types to a similar end; insuring that impure functions never get the same arguments twice by having values that can't be copied or duplicated, so that old values of the "state of the outside world" can't be kept around and reused.
Uniqueness typing is used in Clean
Imperative Functional Programming by Peyton Jones and Wadler is a must read if you are interested in functional IO. The other approaches that they discuss are:
Dialogues which are lazy streams of responses and requests
type Dialogue = [Response] -> [Request]
main :: Dialogue
Continuations - each IO operation takes a continuation as argument
Linear types - the type system restricts you in a way that you cannot copy or destroy the outside state, which means that you can't call a function twice with the same state.
Functional Reactive Programming is another way to handle this.
I was wondering if there were other ways to deal with IO in a pure functional language.
Just adding to the other answers already here:
The title of this paper says it all :-)
You could also look at:
Rebelsky S.A. (1992) I/O trees and interactive lazy functional programming. In: Bruynooghe M., Wirsing M. (eds) Programming Language Implementation and Logic Programming. PLILP 1992. Lecture Notes in Computer Science, vol 631. Springer, Berlin, Heidelberg
When Haskell was young, Lennart Augustsson wrote of using system tokens as the mechanism for I/O:
L. Augustsson. Functional I/O Using System Tokens. PMG Memo 72, Dept Computer Science, Chalmers University of Technology, S-412 96 Göteborg, 1989.
I've yet to find a online copy but I have no pressing need for it, otherwise I suggest contacting the library at Chalmers.
In my second year of University we were "taught" Haskell, I know almost nothing about it and even less about functional programming.
What is functional programming, why and/xor where would I want to use it instead of non-functional programming and am I correct in thinking that C is a non-functional programming language?
One key feature in a functional language is the concept of first-class functions. The idea is that you can pass functions as parameters to other functions and return them as values.
Functional programming involves writing code that does not change state. The primary reason for doing so is so that successive calls to a function will yield the same result. You can write functional code in any language that supports first-class functions, but there are some languages, like Haskell, which do not allow you to change state. In fact, you're not supposed to make any side effects (like printing out text) at all - which sounds like it could be completely useless.
Haskell instead employs a different approach to IO: monads. These are objects that contain the desired IO operation to be executed by your interpreter's toplevel. At any other level they are simply objects in the system.
What advantages does functional programming provide? Functional programming allows coding with fewer potentials for bugs because each component is completely isolated. Also, using recursion and first-class functions allows for simple proofs of correctness which typically mirror the structure of the code.
What is functional programming
There are two different definitions of "functional programming" in common use today:
The older definition (originating from Lisp) is that functional programming is about programming using first-class functions, i.e. where functions are treated like any other value so you can pass functions as arguments to other functions and function can return functions among their return values. This culminates in the use of higher-order functions such as map and reduce (you may have heard of mapReduce as a single operation used heavily by Google and, unsurprisingly, it is a close relative!). The .NET types System.Func and System.Action make higher-order functions available in C#. Although currying is impractical in C#, functions that accept other functions as arguments are common, e.g. the Parallel.For function.
The younger definition (popularized by Haskell) is that functional programming is also about minimizing and controlling side effects including mutation, i.e. writing programs that solve problems by composing expressions. This is more commonly called "purely functional programming". This is made possible by wildly different approaches to data structures called "purely functional data structures". One problem is that translating traditional imperative algorithms to use purely functional data structures typically makes performance 10x worse. Haskell is the only surviving purely functional programming language but the concepts have crept into mainstream programming with libraries like Linq on .NET.
where would I want to use it instead of non-functional programming
Everywhere. Lambdas in C# have now demonstrated major benefits. C++11 has lambdas. There's no excuse not to use higher-order functions now. If you can use a language like F# you'll also benefit from type inference, automatic generalization, currying and partial application (as well as lots of other language features!).
am I correct in thinking that C is a non-functional programming language?
Yes. C is a procedural language. However, you can get some of the benefit of functional programming by using function pointers and void * in C.
May be worth checking out this article on F# "101" on CoDe Mag recently posted.
Also, Dustin Campbell has a great blog where he has posted many articles on his adventures on getting up to speed with F#..
I hope you find these useful :)
EDIT:
Also, just to add, my understanding of functional programming is that everything is a function, or parameters to a function, rather than instances/stateful objects.. But I could be wrong F# is something I am dying to get in to but just dont have the time! :)
John the Statistician's example code does not show functional programming, because when you're doing functional programming, the key is that the code does NO ASSIGNMENTS ( record = thingConstructor(t) is an assignment), and it has NO SIDE EFFECTS (localMap.put(record) is a statement with a side effect). As a result of these two constraints, everything that a function does is fully captured by its arguments and its return value. Rewriting the Statistician's code the way it would have to look, if you wanted to emulate a functional language using C++:
RT getOrCreate(const T thing,
const Function<RT<T>> thingConstructor,
const Map<T,RT<T>> localMap) {
return localMap.contains(t) ?
localMap.get(t) :
localMap.put(t,thingConstructor(t));
}
As a result of the no side-effects rule, every statement is part of the return value (hence return comes first), and every statement is an expression. In languages that enforce functional programming, the return keyword is implied, and the if statement behaves like C++'s ?: operator.
Also, everything is immutable, so localMap.put has to create a new copy of localMap and return it, instead of modifying the original localMap, the way a normal C++ or Java program would. Depending on the structure of localMap, the copy could re-use pointers into the original, reducing the amount of data that has to be copied.
Some of the advantages of functional programming include the fact that functional programs are shorter, and it is easier to modify a functional program (because there are no hidden global effects to take into account), and it is easier to get the program right in the first place.
However, functional programs tend to run slowly (because of all the copying they have to do), and they don't tend to interact well with other programs, operating system processes, or operating systems, which deal in memory addresses, little-endian blocks of bytes, and other machine-specific, non-functional bits. The degree of noninteroperability tends to be inversely correlated with the degree of functional purity, and the strictness of the type system.
The more popular functional languages have really, really strict type systems. In OCAML, you can't even mix integer and floating-point math, or use the same operators (+ is for adding integers, +. is for adding floats). This can be either an advantage or a disadvantage, depending on how highly you value the ability of a type checker to catch certain kinds of bugs.
Functional languages also tend to have really big runtime environments. Haskell is an exception (GHC executables are almost as small as C programs, both at compile-time and runtime), but SML, Common Lisp, and Scheme programs always require tons of memory.
Yes you are correct in thinking that C is a non-functional language. C is a procedural language.
I prefer to use functional programming to save myself repeated work, by making a more abstract version and then using that instead. Let me give an example. In Java, I often find myself creating maps to record structures, and thus writing getOrCreate structures.
SomeKindOfRecord<T> getOrCreate(T thing) {
if(localMap.contains(thing)) { return localMap.get(thing); }
SomeKindOfRecord<T> record = new SomeKindOfRecord<T>(thing);
localMap = localMap.put(thing, record);
return record;
}
This happens very often. Now, in a functional language I could write
RT<T> getOrCreate(T thing,
Function<RT<T>> thingConstructor,
Map<T,RT<T>> localMap) {
if(localMap.contains(thing)) { return localMap.get(thing); }
RT<T> record = thingConstructor(thing);
localMap = localMap.put(thing,record);
return record;
}
and I would never have to write a new one of these again, I could inherit it. But I could do one better than inheriting, I could say in the constructor of this thing
getOrCreate = myLib.getOrCreate(*,
SomeKindOfRecord<T>.constructor(<T>),
localMap);
(where * is a kind of "leave this parameter open" notation, which is a sort of currying)
and then the local getOrCreate is exactly the same as it would have been if I wrote out the whole thing, in one line, with no inheritance dependencies.
If you are looking for a good text on F#
Expert F# is co-written by Don Syme. Creator of F#. He worked on generics in .NET specifically so he could create F#.
F# is modeled after OCaml so any OCaml text would help you learn F# as well.
I find What Is Functional Programming? to be useful
Functional programming is about writing pure functions, about removing
hidden inputs and outputs as far as we can, so that as much of our
code as possible just describes a relationship between inputs and
outputs.
Prefer explicit when param
public Program getProgramAt(TVGuide guide, int channel, Date when) {
Schedule schedule = guide.getSchedule(channel);
Program program = schedule.programAt(when);
return program;
}
over
public Program getCurrentProgram(TVGuide guide, int channel) {
Schedule schedule = guide.getSchedule(channel);
Program current = schedule.programAt(new Date());
return current;
}
A functional language is actively hostile to side-effects. Side-effects are complexity and complexity is bugs and bugs are the devil. A functional language will help you be hostile to side-effects too.