On Fri, 18 Dec 2009 08:55:13 -0800 (PST) IslandRick <rick.braumoel...@gmail.com> wrote: > Can anyone here offer some advice to those who are too ingrained in > using an object-oriented hammer on every nail they see? I know Rich > and Stuart have some good design examples around (I've read many), but > if there are any tutorials that show how to re-envision OO problems in > an FP world, I'd love to see them.
I haven't seen an answer to this, so here's my one-page guide. This is meant more for LISP in general than Clojure specific, but should be better than nothing. I. Functions There have been a number of references to the fact that writing functional programming seems upside-down and/or backwards. That's what you've got here. Clojure's -> macro may help with that, but I'm going to avoid it here. When writing a function in an imperative language, you usually start with arguments, and then pass them through a series of transforms to get the value you want to return, like so: results1 = step1(arguments) results2 = step2(results1) return third_step(results2) To translate that into a function form, either go up from the bottom of the imperative function as you go inwards in the functional version, or start at the inside of the functional version as you go down the imperative one: (third_step (step2 (step1 arguments))) Just like learning a foreign language, if you keep it up you'll eventually stop thinking in imperative terms and translating to functional, and start thinking in functional terms. Actually, that's easier than getting to the point of thinking in a foreign language - or at least it was for me. II: Structure OO programs tend to have objects that invoke each others methods in order to manipulate state and extract information. The typical syntax for a method invocation is: object.method(args) Lisp systems have variables - some of which are functions - instead. So instead of an object that has both it's instance data and the class methods, you have a LISP data structure that holds the "instance data" and a set of functions that manipulate it. A typical invocation (using the names above) looks like: (method object args) As an aside, "class data" winds up in the global variable space. So to write a "class" in LISP, you'd start with the native data structure appropriate for the instance variables. Then you'd write functions that accept one of those as the first argument, and take the appropriate action. I.e. - if you stored a bank account in a hashmap with the balance and id #, you'd do something like (untested code): (defn make-account [initial-balance id] {:balance initial-balance :id id}) (defn deposit [account amount] (make-account (+ (:balance account) amount) id)) (defn withdraw [account amount] (make-account (- (:balance account) amount) id)) (defn balance [account] (:balance account)) and then do (deposit my-account 20) to invoke the deposit "method" on my-account and get an updated account, and so on. It's then up to the caller to do whatever is required with the account to make the state persistent (update a ref, write it to a database, whatever). If you really need to have the methods and data in one object that appears first in the invocation, you can capture them in a closure. Here's a version of the bank account object with an (object :method args) version of the API: (defn make-account [initial-balance id] (let [methods {:balance (fn [] initial-balance) :deposit (fn [amount] (make-account (+ initial-balance amount) id)) :withdraw (fn [amount] (make-account (- initial-balance amount) id))}] (fn [method & args] (apply (methods method) args)))) which would then be used as (my-account :deposit 20), etc. Note that LISP systems with OO subsystems tend to keep the method-first invocation. But they also only seem to be used by a fringe of the LISP community. I'm not going to talk about inheritance - it's sensitive to the underlying LISP, and I don't really know enough about Clojure to do so intelligently. HTH, <mike -- Mike Meyer <m...@mired.org> http://www.mired.org/consulting.html Independent Network/Unix/Perforce consultant, email for more information. O< ascii ribbon campaign - stop html mail - www.asciiribbon.org -- 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