A shell script written in a procedural style (e.g. with Bash or equivalent shell language) will frequently start out by declaring some global variables, then perform some conditional checks (if then else), throw in a few loops (for, while), and ultimately end up with some new values in those initially declared variables that you use as your program's output. If you are feeling particularly intrepid, you might factor out some repetitive operations into separate subroutines defined higher up in the file and then call them as necessary in those aforementioned conditional blocks and loops.
The mental model behind this type of programming is the Universal Turing Machine. Your variables are some internal state that the program instructions are reading and writing, reading and writing, writing and reading until you get to the last instruction that returns some subset of the final variable values. The driving principle is that computation is accomplished by the free mutation of state. A program written in a functional style (e.g. with any Lisp, one of the MLs, Haskell, Clean, etc) begins with a chunk of data, which may either be hard-coded, input from the outside world, or generated internally with a function like "range" or "rand". This piece of data may or may not be stored in one or more global variables. However (and this is HUGE however), these are not generally mutated over the life of the program. That is to say, they are constants. More often than not, you won't even store the initial data in a global variable but will just feed it into a function that processes it and spits out some new data, which is then fed to another function that performs some other processing operation and again spits out some new data. Ultimately, the data that you produce is passed through an arbitrarily long pipeline of functions until the final result is produced and returned by the program. In practice, these function calls are rarely linear and are much more likely to form a branching call tree. But ultimately, the relevant branches of this tree will be traversed and executed in a depth first manner (unless lazy evaluation inserts its magic to reorder some of that computation behind the scenes) and you still get to a final output returned by the last function fall evaluated. The mental model behind this type of programming is Lambda Calculus. There is no mutable state anywhere in a pure functional program, and instead the intermediate results are passed through the call stack from function to function. In practice, because stack sizes are limited, most values passed between functions will be boxed references pointing to memory locations on the heap. However, as far as the functional programmer is concerned, there is no heap and there is no mutable state. Immutable values simply flow seamlessly from one function to the next until the program has finished. The driving principle is that computation is accomplished by transforming data through mapping a set of immutable inputs to an immutable output. Think f(x,y) = z. In order to accomplish this stateless pipeline of data transformations, functions much possess a property called "referential transparency". This means that a function must be able to calculate its outputs deterministically using only its inputs AND without modifying any of its inputs in the process. This property is preserved even when global variables are referenced within the body of a function as long as the values associated with those global variables are constants throughout the lifetime of the program. In practice, very few languages (outside of Haskell) actually try to be completely pure and allow no mutation of state whatsoever. Clojure opts to make all data immutable by default, but provides some special language features (refs, atoms, agents, volatiles) that you can use if you really do want to write an algorithm that involves some mutable state. Unless there is a performance bottleneck (as in numerical computing) or no other sensible way to model the domain (as in some web applications), making use of these features for mutable state is generally frowned upon. When they are really necessary and valuable, however, Clojure's language tools for accomplishing mutation are wonderful because they carefully protect it against concurrency clashes in multi-threated environments. To approach writing a functional program, first think about how to model the computation as a series of data transformations. Then build your program from the bottom up (prototyping and testing it in the REPL) by writing small, referentially transparent functions that describe the lower level operations that you will need. Then build higher level functions on top of those that build up your abstractions in a layer cake style until you reach your entry point function that either takes input data from the outside world or generates it internally and then starts the execution of the function call tree. This is, of course, my attempt at summarizing the mindset that I frequently use when trying to write a new functional program, and I welcome additions or corrections from other folks in this thread to further flesh it out. Best of luck in your functional programming adventures and with Clojure in particular. The FP way of thinking can be a bit tricky to wrap your mind around when coming from a traditional OOP background, but once you grok it, there is a great feeling of freedom and simplicity that emerges from what I suspect many of my fellow Clojurians would agree is a far more elegant and powerful programming paradigm. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.