I spent a bunch of time reading and re-reading your mails. Michal Marczyk's mail (which I read every line of, thank you for taking the time to write it) was the one that made me get what Richard Newman has with utmost patience (THANK YOU!!!!!), I believe, been trying to gently beat into my head from the start.
Richard, your mails were extremely clear (and at this point I've read them all at least 2 or 3 times) but my head was so far away from the problem space that I needed a sufficient amount of beating before I could finally even begin to grok anything. It took me forever to get over the idea that I needed global variables. It was a stupid idee fixe on my part. I just took a piece of my code and re-worked it and made it available at http://www.goland.org/rent_or_sell_refactor.clj. My approach is as follows: #1 - I removed all globally scoped defs (well, I left one, but it's Months-In-Year and is just there for readability purposes). And per Jarkko Oranen's mail I fixed the dashes. :) #2 - I created a function called derived-args. It takes as input a map that is to contain all the arguments provided by the user. It then adds to that map all the derived values. This means that the derived values get calculated exactly one time. It is the output of derived- args that will be put at the very top of the function chain and passed on down. #3 - For some functions I explicitly just list out the arguments they need. But I made a conscious decision not to do that in all cases. I have a number of functions that I call a lot and constantly having to break out their arguments when I call them would quickly grow tedious. So instead I pass those functions the args map and then let them use keys to break out the values. Probably the most egregious example of this pattern is valid-month? I use this in preconditions all over the place. So rather than passing its second argument, months-in-business, as a separate argument I just pass in the whole args map and break out the value inside of valid-month? The benefit of this approach is that all the functions that call valid-month don't themselves have to break out months-in-business in their keys, they can just pass in args. Does http://www.goland.org/rent_or_sell_refactor.clj work more or less the way y'all have been suggesting? In other words have I finally created something that is heading in the 'right' direction? I realize you can't properly judge it until I'm done but I wanted to find out if I was roughly heading in the right direction. Thanks!!!! Yaron On Feb 17, 10:36 pm, Richard Newman <holyg...@gmail.com> wrote: > > I don't expect anyone to actually read, rather I was hoping some folks > > who know Clojure might just glance at it to get the rhythm of the > > math. It's the pattern, not the detail that matters. How should what > > is essentially a monster algebra equation be codified in Clojure? > > I looked at your PDF. > > You express the equations as functions. Turning your equation notation > into function notation -- I'll use Haskell's as an example: > > OpportunityCost = Rent - Sell > > becomes > > opportunityCost r s = r - s > > or in Clojure: > > (defn opportunity-cost [r s] > (- r s)) > > Note that the implicit arguments in your equational notation become > explicit arguments in the functional version. > > How do I compute r and s? Why, with functions of course! Let's take > Sell as an example. > > Sell = HouseSaleProfit0(1 + > RealMonthlyOpportunityCost)^MonthsInBusiness > > which becomes > > (defn sell [hsp-zero rmoc mib] > (* hsp-zero > (exp (+ 1 rmoc) mib))) ; Assuming exp defined. > > Now, assuming that we have Rent, HSP0, RMOC, and MIB calculated (which > follows the same pattern), we compute our OpportunityCost: > > (defn -main [] > ;; TODO: extract user arguments. > ;; ... > (let [hsp-zero (...) ; More calculation. > rmoc (...) > mib (...)] > (println "Opportunity Cost: " > (opportunity-cost rent (sell hsp-zero rmoc mib)))) > > To turn this into your final code, you need only: > > * Keep walking through your formulae until you've expressed everything > as functions; > * Grab the nineteen or so "leaf" values you need from the user, and > plug them into your calls. > > When you have intermediate values, bind them with let, as I show above. > > Note that: > > * Each of the functions stands alone, defined in terms of its > arguments, and follows naturally from your equations > * You can compute any intermediate stage, and print them out, log > them, whatever > * There are no global values or bindings > * You can name each intermediate value using let; your main function > can essentially be a sequential set of intermediate calculations, just > like your PDF. -- 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