Ask HN: Thinking in Functional programming
20 comments
I think most functional programmers don't use TDD. Instead, they write little functions (and macros) that do useful things and approach the problem bottom up, constantly trying things out on the REPL and rewriting the code they have already written.
This way of programming seems incompatible with TDD and I would recommend practicing it in order to start thinking functional.
Paul Graham talks about it here:
http://www.paulgraham.com/progbot.html
I don't program in Lisp or any other functional language, but I use this style a lot programming in Python and code ends up being pretty functional.
This way of programming seems incompatible with TDD and I would recommend practicing it in order to start thinking functional.
Paul Graham talks about it here:
http://www.paulgraham.com/progbot.html
I don't program in Lisp or any other functional language, but I use this style a lot programming in Python and code ends up being pretty functional.
I second the call to SICP; it is, admittedly, very hard to deal with not using recursion after reading the first few chapters, but even outside of that, it will change the way you program.
Reading SICP is like taking a freezing shower; it's a bit of a shock at first, but afterward everything is crisp and clear. Colors are brighter and love is lovelier after you read SICP.
Ok, maybe it's not gold-and-bunnies good, but it's pretty good, and should help remove your cognitive stumbling block.
Reading SICP is like taking a freezing shower; it's a bit of a shock at first, but afterward everything is crisp and clear. Colors are brighter and love is lovelier after you read SICP.
Ok, maybe it's not gold-and-bunnies good, but it's pretty good, and should help remove your cognitive stumbling block.
I agree, strongly. The best imperative Java code I ever wrote was after I worked through exercises in SICP. The book just taught me new ways to think. I'd also recommend "The Little Schemer", for the same reason.
2nd Little Schemer. Cute but hardcore.
I disagree. SICP uses Scheme, which is not a purely functional language. Furthermore, the book doesn't contain that much voodoo, certainly not enough to qualify as a freezing shower.
If you want to learn how to deal with the awkward situations that arise from using a purely functional language, I'd recommend hanging out with the Haskell guys.
SICP is legendary, but for a different reason. Lisp is useful for its simplicity and elegance. Modeling an imperative procedure in the timeless way that Clojure calls for is not necessarily pretty.
If you want to learn how to deal with the awkward situations that arise from using a purely functional language, I'd recommend hanging out with the Haskell guys.
SICP is legendary, but for a different reason. Lisp is useful for its simplicity and elegance. Modeling an imperative procedure in the timeless way that Clojure calls for is not necessarily pretty.
The OP is using Clojure, which is also not purely functional. SICP will be a good choice.
I think I'd normally say "read SICP" but Clojure discourages recursion in favor of it's looping constructs (due to the non-ability to optimize it on the JVM I'm guessing).
That said, SICP will still teach you to think in terms of HOFs and functions as abstractions, so it'll definitely help out. And it's free online, so the only investment is time.
That said, SICP will still teach you to think in terms of HOFs and functions as abstractions, so it'll definitely help out. And it's free online, so the only investment is time.
I believe that you can replace directly recursive
tail-calls with the `recur' special form to achieve
an iterative function manually. If the function is
truly recursive, then Clojure will likely behave
much as any Scheme would.
I haven't looked at the code that gets generated by `recur`, but I'm guessing it creates a trampoline, and it looks a bit limiting. (e.g. you can't recur with variadic functions) That said, probably all of the excercises in SICP could be done with `recur` and `loop,` with a few minor changes. Thanks for the tip.
I'm kind of in the same boat. There are plenty of resources for learning Clojure, but I haven't found any that help with the transition from object oriented programming to functional programming. I read Programming Clojure and I feel like I know the language, but I'm still working on thinking in terms of functional programming. Interestingly, Programming in Scala has helped some. The hybrid functional/object oriented approach has helped introduce functional concepts with a language that doesn't seem so foreign. It can be difficult to pick up a completely different language (different from C-like languages, anyway) as well as a new programming model at the same time. JavaScript: The Good Parts is also good for the same reason.
There's also an F#/C# book scheduled to come out later this year that looks like it might be good for learning the functional thought process: http://www.amazon.com/Functional-Programming-Real-World-Exam...
I found this blog post from Stuart Halloway to be informative as well: http://blog.thinkrelevance.com/2008/9/25/pcl-clojure-chapter...
There's also an F#/C# book scheduled to come out later this year that looks like it might be good for learning the functional thought process: http://www.amazon.com/Functional-Programming-Real-World-Exam...
I found this blog post from Stuart Halloway to be informative as well: http://blog.thinkrelevance.com/2008/9/25/pcl-clojure-chapter...
Stuart Halloway (author of Programming Clojure) came up with a rewrite of Uncle Bob's bowling game: http://github.com/stuarthalloway/clojure-bowling/tree/master
The Mock objects in TDD are there so that after a test you can check that the code under test caused side-effects in dependant objects. (At least, most of the time this is why they exist.)
Functional programming is very much about decoupling "pure functional" computation and side-effects. Using pattern matching you can quite easily write a little machine that performs side-effects given different values. These things are simple and about as useful to unit-test as accessor methods are in oo code. Static typing checks do fine. Also, if it is broken, it tends to be severly broken and not lead to undetected or hard-to-find bugs but simply not work at all.
The interesting code to test is that which is given a bunch of parameters and returns a value that would instruct the side-effectful machine about what to do. This function can be tested with lots of inputs, and you check that it gives the correct instructions (without executing them).
This style of programming exists in OO as well.
Another reason to use Mocks is that they are queried for values that one need control over to rig the unit test. I.e. just a disguised parameters. FP simply doesnt do that.
Functional programming is very much about decoupling "pure functional" computation and side-effects. Using pattern matching you can quite easily write a little machine that performs side-effects given different values. These things are simple and about as useful to unit-test as accessor methods are in oo code. Static typing checks do fine. Also, if it is broken, it tends to be severly broken and not lead to undetected or hard-to-find bugs but simply not work at all.
The interesting code to test is that which is given a bunch of parameters and returns a value that would instruct the side-effectful machine about what to do. This function can be tested with lots of inputs, and you check that it gives the correct instructions (without executing them).
This style of programming exists in OO as well.
Another reason to use Mocks is that they are queried for values that one need control over to rig the unit test. I.e. just a disguised parameters. FP simply doesnt do that.
Some generic advice:
1. Read lots of clojure code. There is clojure-contrib which has lots of little libraries, read through them and see how things are done.
2. I will second the SICP suggestion, atleast the first few chapters. Bottom up programming, building layers of abstraction, is a natural way of doing things in the lisp world.
3. The REPL is your friend. Having a really good working environment is crucial to initial learning as well as later development. I would strongly recommend taking the time to set up one of the clojure working environments(Slime/VimClojure/Enclojure) as a first thing, if you have not already done so.
4. It takes a while, but it gets easier. Keep at it.
1. Read lots of clojure code. There is clojure-contrib which has lots of little libraries, read through them and see how things are done.
2. I will second the SICP suggestion, atleast the first few chapters. Bottom up programming, building layers of abstraction, is a natural way of doing things in the lisp world.
3. The REPL is your friend. Having a really good working environment is crucial to initial learning as well as later development. I would strongly recommend taking the time to set up one of the clojure working environments(Slime/VimClojure/Enclojure) as a first thing, if you have not already done so.
4. It takes a while, but it gets easier. Keep at it.
"3. The REPL is your friend. Having a really good working environment is crucial to initial learning as well as later development. I would strongly recommend taking the time to set up one of the clojure working environments(Slime/VimClojure/Enclojure) as a first thing, if you have not already done so."
I spent substantial amount of time setting up every environment mentioned and ended up with Clojure-Box. I have not tried emacs before; ideally, i should be trying a new language in a known setup, but I prefer the stability of clojure box, so i am taking my baby steps in emacs too.
I spent substantial amount of time setting up every environment mentioned and ended up with Clojure-Box. I have not tried emacs before; ideally, i should be trying a new language in a known setup, but I prefer the stability of clojure box, so i am taking my baby steps in emacs too.
Been there! :). Clojure was my first lisp and I was learning emacs along with it. Looking back, emacs was a really good investment. Also, the ability to develop and debug through remote swank connections is so useful. Slime(with paredit) and swank bring out the best of lisp development.
You should be careful you're looking for something that doesn't exist. That keeps you wondering why you don't find it forever. Perhaps you already have the hang of it, but the purists are getting you down, making you think you don't get it. In practice, there is no such thing as purely functional code, just like there is no such thing as purely object oriented code. If you succeed at avoiding state/mutability and side effects and end up with (less) code that you think is easier to understand, then you are simply doing a good job.
a couple things that i have seen help get into a more functional state of mind:
make everything you can immutable. find a problem where you can build most of it without changing 'the state of the world'. function takes data, spits out answer which is feed into the next.
refactor commonalities from part 1 by passing around functions, closures, etc etc. all your good functional fun toys.
add your mutable core around the outside.
make everything you can immutable. find a problem where you can build most of it without changing 'the state of the world'. function takes data, spits out answer which is feed into the next.
refactor commonalities from part 1 by passing around functions, closures, etc etc. all your good functional fun toys.
add your mutable core around the outside.
Little Schemer, then SICP. For sure. As for TDD, take a look at SchemeUnit, which I've found very handy in testing the exercises in Little Schemer.
SICP is one of the single most valuable and important texts in CS. Little Schemer is structured as a real training regimen to get your mental muscles ready to handle that theory.
SICP is one of the single most valuable and important texts in CS. Little Schemer is structured as a real training regimen to get your mental muscles ready to handle that theory.
Use clojure.test for TDD. There's a bit of documentation here:
http://java.ociweb.com/mark/clojure/article.html#Testing
http://java.ociweb.com/mark/clojure/article.html#Testing
Learn how to implement integers, booleans, pairs, tuples, lists, and trees in lambda calculus (and, more specifically, System F)... and you will be able to think functionally.
I have been finding it very difficult to implement simple problems. I have become familiar with the syntax (got over the = operator typing every other place from my finger memory). While I am comfortable, I feel like I know few keywords without knowing where to use, akin to learning a new language - saying hi, bye, but unable to form a sentence. That is my ponder stop..almost pushes me into procrastination mode
How do I Think in Functional. I catch myself thinking oops(i think of classes,methods..)and i correct myself and end up with something procedural like.
With ref to Uncle Bob's link below , how do I think "inside out"?
II) instead of having another question, I thought of asking it as a sub question from the same link below - TDD in clojure. for one, I don't see a mock object ever created in clojure...please correct me.
I was wondering how to do "TDD" in LISPy languages.
http://blog.objectmentor.com/articles/2009/07/19/uncle-bob-jsps-learning-clojure