So I've been hammocking it up recently on this subject. Just to add more
philosophical perspective - you could look at the universe in two different
ways: from the _inside_, where a thing subjectively experiences the flow of
time, as the world mutates around it; and from the _outside_, where
objectively no time exists, and the history of the universe is a static
network of immutable states, like a unidirectional graph. Animals
understand things from the _inside_ perspective, teleologically, where
things seem dynamic, contextual, and place oriented in time and space.
Physics and philosophy give us the second, ontological understanding. Some
might say the inside perspective is more intuitive while the outside
perspective is more correct or precise.

FP has an ideally unidirectional flow of causality, whereas OOP has loops,
where state flows backwards in the causal chain. A class instance is like a
state machine (to my mind) and that machine moves through time, updating
it's properties. (Banging on things in place)

FP allows you to more easily create an objective universe, where you
control all states from the outside and have absolute control over those
states. This also, however, requires more explicit definition of what you
want to occur, because the context of your transformation is not implicit
in the data itself.

OOP allows you to more easily forget about the complexities of the global,
outside context and operate under the illusion that context is built into
the instance - that the same "thing" is moving across the causal graph,
through time. Unfortunately, as our programs become more complex this
illusion breaks down and our efforts to hide the complexities of the
outside context in looping state machines makes us in fact ignorant of too
much. No, the class is not a duck. No, the method does not actually quack.
It's convenient to pretend like it does, in the small, but the inside,
subjective metaphor becomes a burden in the large.

So while FP sometimes requires more explicit definition of the desired
transformations from one state to the next, you'll end up with a lot more
hair on your head when working with large systems, if Rich and Stu's heads
are any indication :)
John


On Mon, Aug 8, 2016, 11:42 AM Gary Johnson <lambdatro...@gmail.com> wrote:

> 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.
>

-- 
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.

Reply via email to