In OOP, I was structuring my code by composition, having grapes of components, and I was some kind of happy with it...Everything were tidy in boxes :-) What is considered good practices in pure FP ?
I guess just a Haskell Module that exposes the component publicly useful ? Should I play with data types ?
e.g : In Domain Driven Design : Services -> Repositories
ServiceA (serviceX, serviceY, repo1,repo2,repo3)
ServiceB (serviceA, serviceC, serviceZ, repo1,repo2,repo3)
ServiceC (serviceA, serviceB)
Things that change in pure FP is that I don't need an instantiation of all these object, I have just a grape of functions now... The mindset is quite different...
In my current code all the dependencies are hidden like if I was using "static function everywhere in my code" which is terribly bad for testing in OOP...
How should I think in pure FP ?
Functional approach is not that different.
Briefly:
Always go from the most generic to the most specific abstractions. It does apply to the OOP as well, however FP tends to be more explicit on that. In particular, it means that you keep generic not-yet-partially-applied functions far away from modules consuming those.
Composition. It is good to keep your "primitive" functions away from the compositions, especially long ones. You might treat this as a subitem of the #1, though I would classify this as self-important thing. (Warning! Some languages like F# force newcommers to proceed on something like (|>) operators to compose functions. That's not your way: do not evaluate them, otherwise you can't achieve what I am saying here about: make sure your composition indeed produces new function and you decide when to run it).
Never ever ever mix IO or mutable codebase (IO monad in case of Haskell) with pure codebase.
Define type synonymous and new types, when appropriate. Configure your (Haskell) modules to export only those bits, you'd like to be available for consumers rather then entire module (except the case when such a module is rather simple, of course).
Alexander Granin started to write a book about "Functional design and Architecture", he didn't finish that book unfortunately but he did a part of it which is absolutely worth reading : Sources
You'll find all the details here as well :
Architecture modelling, requirements analysis, subsystems design from FP point of view;
Embedded and external DSLs in domain modelling;
Monads as subsystems with effects;
Free monads as functional interfaces;
Other types of functional interfaces;
Inversion of Control in FP (using Free monadic eDSLs);
STM, IO Ref, MVars as concurrent application state;
Lenses;
State, Reader, Writer, RWS, ST monads in subsystems design;
GUI and FP;
Applicability of mainstream techniques and approaches such as UML,SOLID, GRASP;
Interaction with impure subsystems.
I hope somebody will pay him time to finish it :-)
Related
I'm trying to understand how a lot of basic computer science concepts are implemented in functional languages. The point that I can't currently understand is how functional languages and philosophies deal with addresses in memory.
In the context of a very base computer science concept like sorts, how are issues of immutability dealt with efficiently? I know that structural sharing is really needed to keep memory from blowing up. But in my mind this means that relatively simple concepts like selection sort can become quite complicated.
Can someone explain how a functional language deals with in place sorts? Is the idea of being "in place" thrown out and replaced with a data structure that supports structural sharing?
I'm really trying to understand how immutability fits with addresses in memory (think pointers). For example, in an in place sort data is not destroyed, but it is moved to new addresses. Is this considered mutation? I think the answer is yes. But then how can you do things like rotations to balance a binary tree? How do functional programmers think about pointers?
I know that this is relatively hard question to answer, but I feel like its a big issue with respect to really understanding the functional paradigm. Any insights or resources would be greatly appreciated.
Just to get this out of the way:
For example, in an in place sort data is not destroyed, but it is moved to new addresses.
This does not make any sense. If the data is "moved to new addresses", the algorithm, by definition, no longer works "in place".
There is a long tradition of functional programming languages that do not insist on 100% purity. Starting with Lisp, over ML, then OCaml, Scala or Clojure - all these languages have mutable data structures. In "multi-paradigm" languages that have aspects of functional programming, like JavaScript and Python and even Java, you also have mutable data structures. Haskell is rather an exception in its insistence on purity.
Most functional programming languages prefer persistent data structures and algorithms that work on immutable data structures. That is, instead of a mutable hash map, those languages would usually prefer some kind of balanced sorted tree, and instead of mutable list buffers, they would prefer immutable singly-linked lists. For sorting those lists, you could take merge-sort, which is nicely expressible as a pure functional program (but is not in-place, at least not without some considerable extra effort).
Even if you insist on purity, you can still treat the mutable memory of your computer just like yet another part of the mutable "outside world" - as if it were some kind of user input-output, system clock, network communication, or a random number generator. That is, to deal with mutable memory in a pure functional way, you would need two components: first, you would need a way to describe what is to be done with the mutable memory by constructing a "plan" - which is immutable; and then, you would need an interpreter that can take this immutable plan, and apply it to an actual mutable chunk of memory. That is, the interpreter that mutates memory becomes somewhat external to the core of the language, and is treated just like any other part of the "external mutable world".
In languages which do not insist on purity, you can implement both the little domain-specific language for constructing the immutable plans, as well as the interpreter that actually mutates the memory, thereby separating the pure parts from the impure side-effecty mutable parts. For example, Chiusano & Bjarnason in their book "Functional Programming in Scala" have a chapter 14.2.5 literally called "A purely functional in-place quicksort".
In general, in statically typed functional programming, immutability is not the goal in itself. The goal is rather to ensure that half-backed mutable data structures do not escape the narrow scope of the algorithm for which the mutability is advantageous. If you find a way to ensure that, then it means that you can write purely functional programs that make use of mutable memory.
Your confusion comes from promiscuously mixing levels of abstraction.
How is memory allocation handled in your favorite OO garbage-collected language (Python, Java, Ruby, etc)? You don't know. That detail is left to the compiler and/or runtime. You are confusing the semantics of a programming language with an implementation detail for a compiler of that language. I will grant that C/C++ blur the distinction considerably, but that blurring is probably the most salient feature of those languages at this point.
Consider a common associative data structure, the C struct:
struct address
{
char number[10];
char street[100];
char city[50];
char state[15];
};
We know, in advance, what this will look like in memory. But consider a similar data structure in, say, Java:
public class Record {
public int number;
public String street;
public String city;
public String state;
}
How's that going to layout in memory? You don't know. Even if you replace the Strings with character buffers, you don't really know. Obviously javac makes it happen. It's no different with persistent data structures in functional languages: where stuff gets put in memory is up to the compiler, which is not bound by the semantics of the language it's compiling.
I am very new to c++ and confused between what is the difference between modular programming and function oriented programming.I have never done modular programming so I just know modules by definition that it contains functions.So what is the difference between a sequential(function-oriented language)and modular programming?Thanks in advance.
EDIT:
I was reading about C++'s OOP.It started something like what is unstructured programming, than gave a basic idea about structured programming, than modular programming and finally,OOP.
Modular programming is mostly a strategy to reduce coupling in a computer program, mostly by means of encapsulation.
Before modular programming, local coherence of the code was ensured by structured programming, but global coherence was lacking: if you decided that your spell-checking dictionary would be implemented as a red-black tree, then this implementation would be exposed to everyone else in the program, so that the programmer working on, say, text rendering, would be able to access the red-black tree nodes to do meaningful things with them.
Of course, this became hell once you needed to change the implementation of your dictionary, because then you would have to fix the code of other programmers as well.
Even worse, if the implementation detail involved global variables, then you had to be exceedingly careful of who changed them and in what order, or strange bugs would crop up.
Modular programming applied encapsulation to all of this, by separating the implementation (private to the module) from the interface (what the rest of the program can use). So, a dictionary module could expose an abstract type that would only be accessible through module functions such as findWord(word,dictionary). Someone working on the dictionary module would never need to peek outside that module to check if someone might be using an implementation detail.
They are both ways of structuring your code. If your interested in function-oriented programming and want to understand it a bit better, I'd take a look at lisp. C++ isn't truly function oriented as every function should return a value yet C++ functions can return void (making it a procedure rather than a function), so it's not a true functional programming language in the sense.
"I have never done modular programming so I just know modules by definition that it contains functions".
Modules are a level higher than functions.
That's a good start. Think of a function as a unit of work that does something and when you have several functions that you can group in a certain way, you put them in a module. So, string.h has a bunch of functions for working with strings, but you simply include the header and you have access to all those functions directly. You can then reuse those modules in other projects as you'd already used the modules previously and they've been (I assume) debugged and tested and stop people from reinventing the wheel. The whole point is to benefit from the cumulative experience.
I'd suggest you think of a project you'd like and write some functions and think about how you'd like to organize the code for another developer to use.
Hope this is of some use to you.
I believe functional programming leads us to micro services paradigm as for now while modular programming tends to similar to OOP concept.
I am curious how functional languages compare (in general) to more "traditional" languages such as C# and Java for large programs. Does program flow become difficult to follow more quickly than if a non-functional language is used? Are there other issues or things to consider when writing a large software project using a functional language?
Thanks!
Functional programming aims to reduce the complexity of large systems, by isolating each operation from others. When you program without side-effects, you know that you can look at each function individually - yes, understanding that one function may well involve understanding other functions too, but at least you know it won't interfere with some other piece of system state elsewhere.
Of course this is assuming completely pure functional programming - which certainly isn't always the case. You can use more traditional languages in a functional way too, avoiding side-effects where possible. But the principle is an important one: avoiding side-effects leads to more maintainable, understandable and testable code.
Does program flow become difficult to follow more quickly than if a >non-functional language is used?
"Program flow" is probably the wrong concept to analyze a large functional program. Control flow can become baroque because there are higher-order functions, but these are generally easy to understand because there is rarely any shared mutable state to worry about, so you can just think about arguments and results. Certainly my experience is that I find it much easier to follow an aggressively functional program than an aggressively object-oriented program where parts of the implementation are smeared out over many classes. And I find it easier to follow a program written with higher-order functions than with dynamic dispatch. I also observe that my students, who are more representative of programmers as a whole, have difficulties with both inheritance and dynamic dispatch. They do not have comparable difficulties with higher-order functions.
Are there other issues or things to consider when writing a large
software project using a functional language?
The critical thing is a good module system. Here is some commentary.
The most powerful module system I know of the unit system of PLT Scheme designed by Matthew Flatt and Matthias Felleisen. This very powerful system unfortunately lacks static types, which I find a great aid to programming.
The next most powerful system is the Standard ML module system. Unfortunately Standard ML, while very expressive, also permits a great many questionable constructs, so it is easy for an amateur to make a real mess. Also, many programmers find it difficult to use Standard ML modules effectively.
The Objective Caml module system is very similar, but there are some differences which tend to mitigate the worst excesses of Standard ML. The languages are actually very similar, but the styles and idioms of Objective Caml make it significantly less likely that beginners will write insane programs.
The least powerful/expressive module system for a functional langauge is the Haskell module system. This system has a grave defect that there are no explicit interfaces, so most of the cognitive benefit of having modules is lost. Another sad outcome is that while the Haskell module system gives users a hierarchical name space, use of this name space (import qualified, in case you're an insider) is often deprecated, and many Haskell programmers write code as if everything were in one big, flat namespace. This practice amounts to abandoning another of the big benefits of modules.
If I had to write a big system in a functional language and had to be sure that other people understood it, I'd probably pick Standard ML, and I'd establish very stringent programming conventions for use of the module system. (E.g., explicit signatures everywhere, opague ascription with :>, and no use of open anywhere, ever.) For me the simplicity of the Standard ML core language (as compared with OCaml) and the more functional nature of the Standard ML Basis Library (as compared with OCaml) are more valuable than the superior aspects of the OCaml module system.
I've worked on just one really big Haskell program, and while I found (and continue to find) working in Haskell very enjoyable, I really missed not having explicit signatures.
Do functional languages cope well with complexity?
Some do. I've found ML modules and module types (both the Standard ML and Objective Caml) flavors invaluable tools for managing complexity, understanding complexity, and placing unbreachable firewalls between different parts of large programs. I have had less good experiences with Haskell
Final note: these aren't really new issues. Decomposing systems into modules with separate interfaces checked by the compiler has been an issue in Ada, C, C++, CLU, Modula-3, and I'm sure many other languages. The main benefit of a system like Standard ML or Caml is the that you get explicit signatures and modular type checking (something that the C++ community is currently struggling with around templates and concepts). I suspect that these issues are timeless and are going to be important for any large system, no matter the language of implementation.
I'd say the opposite. It is easier to reason about programs written in functional languages due to the lack of side-effects.
Usually it is not a matter of "functional" vs "procedural"; it is rather a matter of lazy evaluation.
Lazy evaluation is when you can handle values without actually computing them yet; rather, the value is attached to an expression which should yield the value if it is needed. The main example of a language with lazy evaluation is Haskell. Lazy evaluation allows the definition and processing of conceptually infinite data structures, so this is quite cool, but it also makes it somewhat more difficult for a human programmer to closely follow, in his mind, the sequence of things which will really happen on his computer.
For mostly historical reasons, most languages with lazy evaluation are "functional". I mean that these language have good syntaxic support for constructions which are typically functional.
Without lazy evaluation, functional and procedural languages allow the expression of the same algorithms, with the same complexity and similar "readability". Functional languages tend to value "pure functions", i.e. functions which have no side-effect. Order of evaluation for pure function is irrelevant: in that sense, pure functions help the programmer in knowing what happens by simply flagging parts for which knowing what happens in what order is not important. But that is an indirect benefit and pure functions also appear in procedural languages.
From what I can say, here are the key advantages of functional languages to cope with complexity :
Functional programming hates side-effects.
You can really black-box the different layers
and you won't be afraid of parallel processing
(actor model like in Erlang is really easier to use
than locks and threads).
Culturally, functional programmer
are used to design a DSL to express
and solve a problem. Identifying the fundamental
primitives of a problem is a radically
different approach than rushing to the brand
new trendy framework.
Historically, this field has been led by very smart people :
garbage collection, object oriented, metaprogramming...
All those concepts were first implemented on functional platform.
There is plenty of literature.
But the downside of those languages is that they lack support and experience in the industry. Having portability, performance and interoperability may be a real challenge where on other platform like Java, all of this seems obvious. That said, a language based on the JVM like Scala could be a really nice fit to benefit from both sides.
Does program flow become difficult to
follow more quickly than if a
non-functional language is used?
This may be the case, in that functional style encourages the programmer to prefer thinking in terms of abstract, logical transformations, mapping inputs to outputs. Thinking in terms of "program flow" presumes a sequential, stateful mode of operation--and while a functional program may have sequential state "under the hood", it usually isn't structured around that.
The difference in perspective can be easily seen by comparing imperative vs. functional approaches to "process a collection of data". The former tends to use structured iteration, like a for or while loop, telling the program "do this sequence of tasks, then move to the next one and repeat, until done". The latter tends to use abstracted recursion, like a fold or map function, telling the program "here's a function to combine/transform elements--now use it". It isn't necessary to follow the recursive program flow through a function like map; because it's a stateless abstraction, it's sufficient to think in terms of what it means, not what it's doing.
It's perhaps somewhat telling that the functional approach has been slowly creeping into non-functional languages--consider foreach loops, Python's list comprehensions...
I read somewhere where rich hickey said:
"I think continuations might be neat
in theory, but not in practice"
I am not familiar with clojure.
1. Does clojure have continuations?
2. If no, don't you need continuations? I have seen a lot of good examples especially from this guy. What is the alternative?
3. If yes, is there a documentation?
When talking about continuations, you’ll have to distinguish between two different kinds of them:
First-class continuations – Continuation-support that is deeply integrated in the language (Scheme or Ruby). Clojure does not support first-class continuations.
Continuation-passing-style (CPS) – CPS is just a style of coding and any language supporting anonymous functions will allow this style (which applies to Clojure too).
Examples:
-- Standard function
double :: Int -> Int
double x = 2 * x
-- CPS-function – We pass the continuation explicitly
doubleCPS :: Int -> (Int -> res) -> res
doubleCPS x cont = cont (2 * x)
; Call
print (double 2)
; Call CPS: Continue execution with specified anonymous function
double 2 (\res -> print res)
Read continuation on Wikipedia.
I don’t think that continuations are necessary for a good language, but especially first-class continuations and CPS in functional languages like Haskell can be quite useful (intelligent backtracking example).
I've written a Clojure port of cl-cont which adds continuations to Common Lisp.
https://github.com/swannodette/delimc
Abstract Continuations
Continuations are an abstract notion that are used to describe control flow semantics. In this sense, they both exist and don't exist (remember, they're abstract) in any language that offers control operators (as any Turing complete language must), in the same way that numbers both exist (as abstract entities) and don't exist (as tangible entities).
Continuations describe control effects such as function call/return, exception handling, and even gotos. A well founded language will, among other things, be designed with abstractions that are built on continuations (e.g., exceptions). (That is to say, a well-founded language will consist of control operators that were designed with continuations in mind. It is, of course, perfectly reasonable for a language to expose continuations as the only control abstraction, allowing users to build their own abstractions on top.)
First Class Continuations
If the notion of a continuation is reified as a first-class object in a language, then we have a tool upon which all kinds of control effects can be built. For example, if a language has first-class continuations, but not exceptions, we can construct exceptions on top of continuations.
Problems with First-Class Continuations
While first-class continuations are a powerful and useful tool in many cases, there are also some drawbacks to exposing them in a language:
Different abstractions built on top of continuations may result in unexpected / unintuitive behavior when composed. For example, a finally block might be skipped if I use a continuation to abort a computation.
If the current continuation may be requested at any time, then the language run-time must be structured so that it is possible to produce some data-structure representation of the current continuation at any time. This places some degree of burden on the run-time for a feature which, for better or worse, is often considered "exotic". If the language is hosted (such as Clojure is hosted on the JVM), then that representation must be able to fit within the framework provided by the hosting platform. There may also be other features a language would like to maintain (e.g., C interop) which restrict the solution space. Issues such as these increase the potential of an "impedence mismatch", and can severely complicate development of a performant solution.
Adding First-Class Continuations to a Language
Through metaprogramming, it is possible to add support for first-class continuations to a language. Generally, this approach involves transforming code to continuation-passing style (CPS), in which the current continuation is passed around as an explicit argument to each function.
For example, David Nolen's delimc library implements delimited continuations of portions of a Clojure program through a series of macro transforms. In a similar vein, I have authored pulley.cps, which is a macro compiler that transforms code into CPS, along with a run-time library to support more core Clojure features (such as exception handling) as well as interop with native Clojure code.
One issue with this approach is how you handle the boundary between native (Clojure) code and transformed (CPS) code. Specifically, since you can't capture the continuation of native code, you need to either disallow (or somehow restrict) interop with the base language or place a burden on the user of ensuring the context will allow any continuation they wish to capture to actually be captured.
pulley.cps tends towards the latter, although some attempts have been made to allow the user to manage this. For instance, it is possible to disallow CPS code to call into native code. In addition, a mechanism is provided to supply CPS versions of existing native functions.
In a language with a sufficiently strong type system (such as Haskell), it is possible to use the type system to encapsulate computations which might use control operations (i.e., continuations) from functionally pure code.
Summary
We now have the information necessary to directly answer your three questions:
Clojure does not support first-class continuations due to practical considerations.
All languages are built on continuations in the theoretical sense, but few languages expose continuations as first-class objects. However, it is possible to add continuations to any language via, e.g., transformation into CPS.
Check out the documentation for delimc and/or pulley.cps.
Is continuation a necessary feature in a language?
No. Plenty of languages don't have continuations.
If no, dont you need continuations? I have seen a lot of good examples especially from this guy. What is the alternative?
A call stack
A common use of continuations is in the implementation of control structures for: returning from a function, breaking from a loop, exception handling etc. Most languages (like Java, C++ etc) provide these features as part of the core language. Some languages don't (e.g: Scheme). Instead, these languages expose continuatiions as first class objects and let the programmer define new control structures. Thus Scheme should be looked upon as a programming language toolkit, not a complete language in itself.
In Clojure, we almost never need to use continuations directly, because almost all the control structures are provided by the language/VM combination. Still, first class continuations can be a powerful tool in the hands of the competent programmer. Especially in Scheme, continuations are better than the equivalent counterparts in other languages (like the setjmp/longjmp pair in C). This article has more details on this.
BTW, it will be interesting to know how Rich Hickey justifies his opinion about continuations. Any links for that?
Clojure (or rather clojure.contrib.monads) has a continuation monad; here's an article that describes its usage and motivation.
Well... Clojure's -> implements what you are after... But with a macro instead
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.