I must say that I find Richard's suggestions to be very reasonable, but I'd like to add my own take... This is meant as a step-by-step account of my thinking process, so it starts out with a statement of the basics. Skim & skip if you prefer.
The problem to be solved is basically a huge calculation. When written out -- for the purpose of defining the problem -- in the usual mathematical notation, it turns out to depend on multiple free variables (inflation rate, interest on the mortgage etc.); then there's a bunch of named parameters / dependent variables whose values are derived from those free variables. So, the natural thing to do is what you do in that .pdf you posted: you break it down into a bunch of equations defining the dependent variables in the above in terms of the free variables and / or previously defined dependent variables plus one inequality of the form, say, rent-profit <= sale-profit, whose truth or falsity is to be established. Now, an imperative programme to calculate whether rent-profit does or does not exceed sale-profit would proceed as follows: free-variable-1 = some-value-1 free-variable-2 = some-value-2 ... dependent-variable-1 = some-function-of(free-variable-k, free-variable-l, free-variable-n) ... answer = rent-profit-function(...some-arguments...) <= sale-profit-function(...some-arguments...) A functional programme, on the other hand, would contain no section to correspond to the free-variable-n assignments at all. Then in place of all the dependent-variable-m assignments it would contain function definitions: (defn calculate-dependent-variable-1 [free-var-k, free-var-l ...] ...) When you start composing those, you do things like (defn calculate-problematic-quantity [...all free vars needed in side...] (let [dep-var-1 (calculate-dependent-variable-1 ...the arguments...) dep-var-2 (calculate-dependent-variable-2 ...the arguments...) ...] ...combine the free-vars received as arguments with the dep-vars calculated in the bindings portion of the let form to produce the return value...)) Feel free to receive dependent variables as arguments if you're likely to have multiple functions depend on them in some way: (defn f1 [dep-var-1 ...] ...) (defn f2 [dep-var-1 ...] ...) (defn function-using-f1-f2 [...args...] (let [dep-var-1 (calculate-dependent-variable-1 ...args...) f1-val (f1 dep-var-1 ...) f2-val (f2 dep-var-1 ...) ...)) Then once you do have all the building blocks in place, you'd write one monster entry function taking some values for the free variables -- perhaps in the form of a map -- and have it call the building-block-functions, perhaps using the sequential binding facitility of the let special form to name intermediate values for use in further computational steps. This process strikes me as incredibly similar to what you would do if you were to solve the equations by hand: you break them down into well-defined intermediate steps, write down recipes defining the exact nature of those steps, then write down formulae combining the results of those intermediate steps. You strive to reduce the number of free variables any single equation depends on, preferring to break down huge equations into smaller ones which depend on parameters defined by further small equations. Etc. In Haskell you can even write the "main equations" on top, followed by the helper equations lower down, possibly limiting the scope of the latter: calculateFoo x y z = fooComponent1 + fooComponent2 where fooComponent1 = (some expression in x, y, z) fooComponent2 = (some expression in x, y, z) In Clojure you'd use a let form for that, which may be a blessing or a curse both syntactically (the issue of what you put on the top) and semantically (because "where" and "let" bindings are mutually recursive in Haskell). The basic idea stays the same, though, with Haskell's syntax perhaps making it slightly more obvious how the Haskell functions involved are almost direct transliterations of the mathematical, purely declarative statements of the nature of the calculational subproblems. That syntax is something you'd actually have to learn the (considerable) quirks of, so some find the Lisp syntax-less approach ultimately more manageable (myself included). Anyway, I'd say that your project is the perfect dream use case for functional programming... I wonder if I've managed to expose some of my reasons for feeling this way? :-) An additional note: given the purpose of the calculations involved, I guess you'll want to be well-assured of the correctness of the result. Using maps to pass around named values may help with that; I'd even go as far as using assertions and / or preconditions to make sure that each function does receive all the values it expects in its argument map. What I *would not* do, however, is to mass around one huge map all the time; I'd still only give each function the exact arguments it must receive, putting them in a map only to avoid silly bugs like (f interest inflation) instead of (f inflation interest). The latter may be hard to catch; a misdefined map like {:interest inflation :inflation interest} is easy to catch in code review (and not very likely to be written in the first place). All best, Michał -- 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