Re: newbie question: Please help me stop creating constructors
On Mar 1, 9:55 am, Richard Newman holyg...@gmail.com wrote: (defn house-sale-profit [house-sales-price house-sale-expenses] (- house-sales-price house-sale-expenses)) I'd like to note that if you do this, you might just as well use the - function directly. It's not as flexible if the profit calculation changes, but until there's a real need, it just feels like overabstraction. (let [profit (- house-sales-price house-sale-expenses)] ...) is perfectly reasonable. The same applies to calculating months-in- business. -- 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
Re: newbie question: Please help me stop creating constructors
On Thu, Feb 18, 2010 at 3:36 PM, Richard Newman holyg...@gmail.com wrote: 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)) What to do if we don't know which of the equation variables are unknowns? Let's say that the user may choose whether to input Rent and Sell, or Rent and opportunityCost. I can imagine writing some code like this: (defn opportunity-cost [opportunity-cost-in rent-in sell-in] (if (nil? opportunity-cost-in) (- rent-in sell-in) opportunity-cost-in)) (defn rent [opportunity-cost-in rent-in sell-in] (if (nil? rent-in) ...) (defn sell [opportunity-cost-in rent-in sell-in] (if (nil? sell-in) ...) but complexity of such expressions quickly grows as dependencies between variables become more complex. Is there any technique/framework for handling such calculations automatically? I have a vague impression that this is what logic programming languages are about. How would one implement such calculations in Clojure? Going further, what to do if the equation is underspecified (for example, if the user has only input Rent) and we want to do something more useful than just fail. This would require us to do the calculations symbolically. Can Clojure help here somehow? What would be a minimal CAS framework in Clojure? -Andrzej -- 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
Re: newbie question: Please help me stop creating constructors
I'd like to note that if you do this, you might just as well use the - function directly. Of course; this was merely for the sake of illustration. -- 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
Re: newbie question: Please help me stop creating constructors
but complexity of such expressions quickly grows as dependencies between variables become more complex. Is there any technique/framework for handling such calculations automatically? I have a vague impression that this is what logic programming languages are about. How would one implement such calculations in Clojure? As Johnny mentioned: this is a solver. Doing it in Clojure means writing something rather more complicated than a simple calculator! Clojure is not a logic programming language. You might find a cell/dataflow framework useful, which essentially gives you spreadsheet-like dataflow: http://richhickey.github.com/clojure-contrib/dataflow-api.html best introduced in its original Common Lisp form: http://smuglispweeny.blogspot.com/2008/02/cells-manifesto.html but you'll still have to do some manual decision-making. (Just like in a spreadsheet, you have to write the formulae...) You might also (depending on how things fall out) find some kind of table-based or multimethod-based approach to be adequate (e.g., making two different kinds of `sell` evaluation based on whether some value is nil). That will reduce the number of explicit branches in your code. If neither of those helps, then your best bet is to spend a little time with, say, Mathematica, Excel, and Prolog (or one of its successors). Those might well be better systems for handling this kind of web of dependencies. If you want a Lisp syntax for Prolog, try Allegro Common Lisp. http://www.franz.com/products/prolog/index.lhtml -- 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
Re: newbie question: Please help me stop creating constructors
I don't think that dataflow works quite right in my case because, if I understood Mr. Straszheim's posts correctly then dataflows can't have cycles and I have cycles all over the place. Unfortunately this isn't visible in the example I gave because I used Sell which doesn't have cycles. Rent on the other hand is recursive and cyclic. On Mar 1, 7:31 am, Richard Newman holyg...@gmail.com wrote: but complexity of such expressions quickly grows as dependencies between variables become more complex. Is there any technique/framework for handling such calculations automatically? I have a vague impression that this is what logic programming languages are about. How would one implement such calculations in Clojure? As Johnny mentioned: this is a solver. Doing it in Clojure means writing something rather more complicated than a simple calculator! Clojure is not a logic programming language. You might find a cell/dataflow framework useful, which essentially gives you spreadsheet-like dataflow: http://richhickey.github.com/clojure-contrib/dataflow-api.html best introduced in its original Common Lisp form: http://smuglispweeny.blogspot.com/2008/02/cells-manifesto.html but you'll still have to do some manual decision-making. (Just like in a spreadsheet, you have to write the formulae...) You might also (depending on how things fall out) find some kind of table-based or multimethod-based approach to be adequate (e.g., making two different kinds of `sell` evaluation based on whether some value is nil). That will reduce the number of explicit branches in your code. If neither of those helps, then your best bet is to spend a little time with, say, Mathematica, Excel, and Prolog (or one of its successors). Those might well be better systems for handling this kind of web of dependencies. If you want a Lisp syntax for Prolog, try Allegro Common Lisp. http://www.franz.com/products/prolog/index.lhtml -- 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
Re: newbie question: Please help me stop creating constructors
Richard, I spent quite a bit of time thinking about what you said. So I rewrote the whole kit and kaboodle. My understanding of your mail led me to take the approach of defining functions who take as arguments the invariant values and who output functions that take variant values. For example: (defn house-sale-profit [house-sales-price house-sale-expenses] (fn [m] (- (house-sales-price m) (house-sale-expenses m In this example both house-sales-price and house-sale-expenses are actually themselves functions which I would have had to have called previously to get their instance functions and passed in as arguments. To test out this idea I decided to implement all the functions needed to implement the sell function from my paper. But when I was done and wanted to actually calculate a sell value I had to write something like: (defn sell-calculator [{:keys [real-monthly-opportunity-cost months-to-find-tenant months- in-lease lease-cycles months-to-sell excise-tax months-in-loan original-loan-amount monthly-loan-interest other- sales-fees-0 monthly-inflation-rate selling-agent-fee-type selling-agent-fee-number buying-agent-fee- type buying-agent-fee-number house-sales-price-0 loan-month-at-start]}] (let [inflate (inflate monthly-inflation-rate) house-sales-price (house-sales-price house-sales-price-0 inflate) buying-agent-fee (agent-fee inflate buying-agent-fee-type buying-agent-fee-number house-sales-price) selling-agent-fee (agent-fee inflate selling-agent-fee-type selling-agent-fee-number house-sales-price) other-sales-fees (other-sales-fees other-sales-fees-0 inflate) remaining-loan-balance (remaining-loan-balance months-in-loan original-loan-amount monthly-loan-interest loan-month-at-start) house-sale-expenses (house-sale-expenses house-sales-price excise-tax buying-agent-fee selling-agent-fee other-sales-fees remaining-loan-balance) house-sale-profit (house-sale-profit house-sales-price house- sale-expenses) months-in-business (months-in-business months-to-find-tenant months-in-lease lease-cycles months-to-sell)] (sell house-sale-profit real-monthly-opportunity-cost months-in- business))) Writing the previous wasn't much fun and I recognized that I would have to build the equivalent for testing all the various sub-functions and I can only imagine what trying to do any kind of refactoring or adding new functions would be like. But then it occurred to me that all I was really doing was building up a parse tree and that is something that computers are really good at. So why not just have the computer do the work for me? So I wrote a function called fill-map. It takes a keyword that maps to the name of a function and a map that contains all the user arguments. It turn returns a map that contains the submitted function and all of its dependent functions. (Having the whole map including the dependent functions is extremely useful for testing) (defn fill-map ([func-name-keyword filled-map] (fill-map func-name-keyword filled- map [])) ([func-name-keyword filled-map ancestorvector] {:pre [(keyword? func-name-keyword) (map? filled-map) (vector? ancestorvector)]} (if (contains? filled-map func-name-keyword) filled-map (do (throw-if-in-seq func-name-keyword ancestorvector) (let [func-name-symbol (keyword-to-symbol func-name-keyword) func (func-keyword-to-func-pointer func-name-keyword) func-arguments (func-keyword-to-func-keyword-arglist func- name-keyword) ancestorvector (conj ancestorvector func-name-keyword) filled-map (reduce #(fill-map %2 %1 ancestorvector) filled- map func-arguments)] (assoc filled-map func-name-keyword (apply func (map #(filled- map %1) func-arguments I also wrote: (defn stack-em [func-name-keyword filled-map] ((fill-map func-name-keyword filled-map) func-name-keyword)) So now I can just say: (defn sell-calculator [userargs] (stack-em :sell userargs)) The previous creates the same parse map as I manually created above but in a fully automated fashion. And if I change any of the signatures, dependencies, stick in new things, etc. it's no problem, everything gets automatically regenerated. You can see the whole program at http://www.goland.org/simple-reverse-rent-or-sell.clj So is this the way you would approach this problem in Clojure? Thanks, Yaron On Feb 19, 10:15 pm, Richard Newman holyg...@gmail.com wrote: I have to think that's preferable to submitting 30+ arguments to rent and sell. Or were you suggesting a different approach? The different approach only works with a different approach :) The way you've structured run-calculator, using the map is best, because 30 arguments is crazy. Your need to pass 30 arguments to rent and sell because they need to obtain or compute all of their intermediate values. You have a tree, with rent and sell doing all the work. The alternative
Re: newbie question: Please help me stop creating constructors
So I rewrote the whole kit and kaboodle. My understanding of your mail led me to take the approach of defining functions who take as arguments the invariant values and who output functions that take variant values. For example: I'm not sure how much functional programming experience you have, but you've essentially discovered a kind of currying. http://en.wikipedia.org/wiki/Currying That is, you're taking a function house-sale-profit, in terms of house- sales-price (a function), house-sale-expenses (a function), and m, and fixing the first two values, returning a function in terms of m. This is seamless in Haskell; less so in Clojure. See the built-in function `partial`. When you wrote (defn house-sale-profit [house-sales-price house-sale-expenses] (fn [m] (- (house-sales-price m) (house-sale-expenses m and used it like this: (let [... house-sale-profit-fn (house-sale-profit house-sales-price house-sale-expenses) ...] ...) you could just as easily have written: (defn house-sale-profit [house-sales-price house-sale-expenses m] (- (house-sales-price m) (house-sale-expenses m))) and used it like this: (let [... house-sale-profit-fn (partial house-sale-profit house-sales- price house-sale-expenses) ...] ...) This makes house-sale-profit a perfectly normal function, but still allows you to partially evaluate it to yield a closure. In this example both house-sales-price and house-sale-expenses are actually themselves functions which I would have had to have called previously to get their instance functions and passed in as arguments. By doing this you're pretty much writing your own interpreter, as you figured out :) So is this the way you would approach this problem in Clojure? No. (However, consider that I'm as likely to be wrong as anybody else, and also that you're learning a ton by trying different approaches!) I would do things much more simply: rather than (to take your example) defining house-sale-profit in terms of two functions and a month value, which is threaded into those functions (providing opportunity for breakage should the signature of, say, house-sales-price change), I would simply *define house-sale-profit in terms of the sales price and expenses*. Rely on the price and the expenses having been calculated outside the function. No nonsense with throw-if-in-seq and all the other complicated machinery you have built. (defn house-sale-profit [house-sales-price house-sale-expenses] (- house-sales-price house-sale-expenses)) This is the literal definition of profit; you can write tests for this with just two numbers. If your expenses don't care about a number of months, or they care about something else, then just pass in a different value -- no futzing with functions. It's more efficient, too -- no anonymous functions. For a single invocation you're only using one value of m, with one house sales price, and one set of expenses. Just put them in the let! (let [m from the user price ... expenses ... profit (house-sale-profit price expenses) ...] ...) I've done this for some of your functions: http://twinql.com/tmp/rent.clj I haven't tried actually using it to compute anything, but it should give you an idea of the style I'd use. I would guess that the whole program, neatly laid out and commented, should come to only a couple hundred lines. Each individual function is trivially testable and reusable, as is every composition of functions that goes into computing the final answer. If you want to be neater, split `sell-calculator` into two or more functions; perhaps one which walks through the rent calculation, and another which walks through the house sale calculation. That way each individual function remains short and sweet. Note that I still curry some functions (e.g., inflate), and if I bothered to implement the agent fees (which are inflation-linked) I might do it by passing in that curried `inflate` function. (Then again, I might not, if I can phrase them in terms of constant values which are computed elsewhere.) Most of the intermediate values are simply computed directly. Note also that, if you wished, you could completely eliminate the `let` form, turning this whole calculation into a single (slightly redundant) tree. I don't advocate that as particularly good style, but it's possible. Ultimately, all you're doing here is writing a set of functions and combining them together to produce an answer: a simple matter of traditional programming. It's not rocket surgery (as they say nowadays), and so any solution which requires you to write code to detect recursive calls, look up function names at runtime, manage a huge intermediate map of results, etc. is probably a sign that you're over-engineering things. I would have used almost the
Re: newbie question: Please help me stop creating constructors
With this approach how would I test the individual functions defined inside of the let? Wouldn't they be invisible to me and the test framework which would only see sell-or-rent? On Feb 18, 4:27 pm, John Williams j...@pobox.com wrote: I'm no Clojure guru myself, but one approach you may want to consider is nest all your auxiliary functions inside the main function, and use ordinary let-bindings the same way you've been trying to use global bindings: (defn sell-or-rent [{:keys [supplied-1 supplied-2]}] (let [derived-1 (+ 1 supplied-1) derived-2 (* 2 supplied-2)] (letfn [(f [x y z] ...) (g [x] ...)] ...))) This has the disadvantage of indenting all your helper functions much more than they would be otherwise, but it gets the job done without any messy global variables or thunks. If you want to expose more functions than just sell-or-rent, you could write some very OO-flavored code: ;; Define a function to create objects. (defn pseudo-constructor [{:keys [supplied-1 supplied-2]}] (let [member-var-1 (+ 1 supplied-1) member-var-2 (* 2 supplied-2)] (letfn [(private-method-1 [] priv1) (private-method-2 [] priv2)] {:public-method-1 (fn [x y z] pub1) :public-method-2 (fn [x y] pub2)}))) ;; Use the object. (let [obj (pseudo-constructor {:supplied-1 1 :supplied-2 2})] (println ((:public-method-1 obj) x y z)) (println ((:public-method-2 obj) x y))) --jw On Mon, Feb 15, 2010 at 11:24 AM, Yaron ygol...@gmail.com wrote: I am writing a calculator to figure out if I should sell or rent my home using Clojure. This is my first Clojure program so I'm about as wet behind the ears as it gets. So far everything is actually going really well (reminds me of the fun I had with Scheme in college) but for one thing. My calculator needs 30+ arguments from the user in order to run. Furthermore I have a bunch of secondary values that are derived from the arguments the user submits. So imagine the user submits a value A. I will have a value B whose definition will be something like (+ 1 A) (yes, more complex in reality, but you get the idea). If I were back in Java or C# I would define a class, submit A (and it's 29+ friends) in the constructor and then create a property on the class B. In Clojure I have taken a different approach. I first create (def *A* 3) where 3 is a completely bogus value I just made up. Then at run time I use bindings to re-bind A to the actual value the user passed in. But my problem is, what to do about B? I thought of doing something like (def *B* 3) and then in the binding passing in a function like (defn B-Gen [] (+ *A* 1)) to create a new binding to B but I quickly realized this would be a bug inducing nightmare. If I forget to include one of the derived values in the binding or put them in the wrong order then I would get the wrong value. So what I currently do is: (def *A* 3) ; A bogus value that will later be rebound (defn B [] (+ *A* 3)) The good news is, that this works and doesn't require any book keeping. The bad news is that it's ugly. If I want to do something trivial like divide B by 2 I have to call B as a function(/ (B) 2) instead of the more natural (/ B 2). And of course this approach is pretty unfortunate from a performance perspective as I'm constantly having to recalculate what are effectively static values. Yes, I could use memoization but many of these values are pretty trivial (usually just algebra equations) and I suspect the overhead of memoization exceeds the perf improvement. But in any case the whole approach of having to take what really are static values and turn them into functions feels really hacky. So my guess is that I'm thinking about this problem the wrong way. I'm stuck in my old imperative/OO constructor world. What's the right way to think about primary values that will be rebound (once) that then have dependent values that need to be recalculated when that rebinding happens? Thanks, Yaron -- 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.comclojure%2bunsubscr...@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 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
Re: newbie question: Please help me stop creating constructors
Right, nesting everything inside a single function makes it impossible to unit test the inner functions--they don't even have names in the global scope! In retrospect, I think the solution I posted is more cute than it is practical. Passing around a map of intermediate values seems to be the winner all around, but it still seems a little odd to me. Idiomatic Clojure code manipulates maps far more than I've seen in any other language. On Fri, Feb 19, 2010 at 11:30 AM, Yaron ygol...@gmail.com wrote: With this approach how would I test the individual functions defined inside of the let? Wouldn't they be invisible to me and the test framework which would only see sell-or-rent? On Feb 18, 4:27 pm, John Williams j...@pobox.com wrote: I'm no Clojure guru myself, but one approach you may want to consider is nest all your auxiliary functions inside the main function, and use ordinary let-bindings the same way you've been trying to use global bindings: (defn sell-or-rent [{:keys [supplied-1 supplied-2]}] (let [derived-1 (+ 1 supplied-1) derived-2 (* 2 supplied-2)] (letfn [(f [x y z] ...) (g [x] ...)] ...))) This has the disadvantage of indenting all your helper functions much more than they would be otherwise, but it gets the job done without any messy global variables or thunks. If you want to expose more functions than just sell-or-rent, you could write some very OO-flavored code: ;; Define a function to create objects. (defn pseudo-constructor [{:keys [supplied-1 supplied-2]}] (let [member-var-1 (+ 1 supplied-1) member-var-2 (* 2 supplied-2)] (letfn [(private-method-1 [] priv1) (private-method-2 [] priv2)] {:public-method-1 (fn [x y z] pub1) :public-method-2 (fn [x y] pub2)}))) ;; Use the object. (let [obj (pseudo-constructor {:supplied-1 1 :supplied-2 2})] (println ((:public-method-1 obj) x y z)) (println ((:public-method-2 obj) x y))) --jw On Mon, Feb 15, 2010 at 11:24 AM, Yaron ygol...@gmail.com wrote: I am writing a calculator to figure out if I should sell or rent my home using Clojure. This is my first Clojure program so I'm about as wet behind the ears as it gets. So far everything is actually going really well (reminds me of the fun I had with Scheme in college) but for one thing. My calculator needs 30+ arguments from the user in order to run. Furthermore I have a bunch of secondary values that are derived from the arguments the user submits. So imagine the user submits a value A. I will have a value B whose definition will be something like (+ 1 A) (yes, more complex in reality, but you get the idea). If I were back in Java or C# I would define a class, submit A (and it's 29+ friends) in the constructor and then create a property on the class B. In Clojure I have taken a different approach. I first create (def *A* 3) where 3 is a completely bogus value I just made up. Then at run time I use bindings to re-bind A to the actual value the user passed in. But my problem is, what to do about B? I thought of doing something like (def *B* 3) and then in the binding passing in a function like (defn B-Gen [] (+ *A* 1)) to create a new binding to B but I quickly realized this would be a bug inducing nightmare. If I forget to include one of the derived values in the binding or put them in the wrong order then I would get the wrong value. So what I currently do is: (def *A* 3) ; A bogus value that will later be rebound (defn B [] (+ *A* 3)) The good news is, that this works and doesn't require any book keeping. The bad news is that it's ugly. If I want to do something trivial like divide B by 2 I have to call B as a function(/ (B) 2) instead of the more natural (/ B 2). And of course this approach is pretty unfortunate from a performance perspective as I'm constantly having to recalculate what are effectively static values. Yes, I could use memoization but many of these values are pretty trivial (usually just algebra equations) and I suspect the overhead of memoization exceeds the perf improvement. But in any case the whole approach of having to take what really are static values and turn them into functions feels really hacky. So my guess is that I'm thinking about this problem the wrong way. I'm stuck in my old imperative/OO constructor world. What's the right way to think about primary values that will be rebound (once) that then have dependent values that need to be recalculated when that rebinding happens? Thanks, Yaron -- 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
Re: newbie question: Please help me stop creating constructors
Looks pretty good to me. I like your use of preconditions and the number of tests. I think your indentation is a little deep (I go for two spaces, myself), and I never use :Capital keywords, but otherwise great. The indentation was just what the Clojure plugin for Eclipse was set to by default. As for capitalization I've never been completely clear on what the normal naming rules in Clojure are. You might be interested in the `are` macro to make your test code simpler: Thanks for pointing this out. Very useful. I've already started adapting some of my tests. One suggestion: Rather than having two phases of derived args, and calling functions with arguments like: (total-house-depreciation args-and-mib) I'd save that step and adjust total-house-depreciation, year-sold, etc. to take an additional months-in-business argument: (defn total-house-depreciation The total amount of depreciation on the rental property taken over the period we were in business [args months-in-business] ...) Then you can change your derived-args function to: (defn derived-args [{:keys [months-to-find-tenant months-in-lease lease-cycles months-to- sell] :as args}] (assoc args :months-in-business (months-in-business months-to-find-tenant months-in-lease lease-cycles months-to-sell) :total-house-depreciation (total-house-depreciation args months- in-business) :year-sold (year-sold args months-in-business) :months-actively-renting (months-actively-renting months-to-find- tenant months-in-lease lease-cycles))) No lets at all. The reason why I didn't make months-in-business an explicit arg for total-house-depreciation and year-sold is because both functions are thin wrappers for underlying functions that take args. So if I broke out months-in-business at the top I'd just have to invent the equivalent of the args-and-mib variable farther down to give the functions they are wrapping what they are expecting. BTW, the only place I had to use let in anything even like this manner was derived-args. Everywhere else I can just pass args with no voodoo, no lets, nothing. All the 'voodoo' is just in derived-args and creating derived-args. You'll see then that it's a small step from there to my suggested functional end game, which eliminates the passing of the args map altogether: derived-args would extract all the named arguments and pass just the specific ones to each function. No big deal, though; there are advantages to the map approach. This is the one paragraph I'm not sure I completely follow. derived- args is a pretty dumb (as in intelligence) function. It just takes the core args (the ones passed in by the user) and augments them with some convenience values that are static for the whole run of the calculator. So without the map top level functions like Rent, Sell, MonthlyRentalProfit, etc. would literally need to take 30+ arguments (I'm not exaggerating btw). My root function looks like: (defn run-calculator [args] (let [derived-args (derived-args args)] (- (rent derived-args) (sell derived-args I have to think that's preferable to submitting 30+ arguments to rent and sell. Or were you suggesting a different approach? Looking good! -R Mega thanks!!! Yaron -- 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
Re: newbie question: Please help me stop creating constructors
I have to think that's preferable to submitting 30+ arguments to rent and sell. Or were you suggesting a different approach? The different approach only works with a different approach :) The way you've structured run-calculator, using the map is best, because 30 arguments is crazy. Your need to pass 30 arguments to rent and sell because they need to obtain or compute all of their intermediate values. You have a tree, with rent and sell doing all the work. The alternative approach is to make your functions take the intermediate values as arguments explicitly, and define those functions much like your equations. You then bind the intermediate values in a let... perhaps best shown by example. Instead of (defn house-depreciation The amount of depreciation that can be claimed on Federal Income Taxes in year y [y args] {:pre [(valid-year? y args)]} (cond ( y 27) 0 ( y 27) (/ (house-sales-price 0 args) 27.5) (= y 27) (* 0.5 (/ (house-sales-price 0 args) 27.5 you would write (defn house-depreciation The amount of depreciation that can be claimed on Federal Income Taxes in year y [y house-sale-price] {:pre [(valid-year? y args)]} (cond ( y 27) 0 ( y 27) (/ house-sale-price 27.5) (= y 27) (* 0.5 (/ house-sale-price 27.5 This transformation applies to all of your functions, so even rent and sell get defined in terms of their intermediate values, just as I showed in a much earlier email. Your calculator would become (defn run-calculator [args] (let [... house-sale-price (some-fn ... some-arg) ... house-depreciation (house-depreciation y house-sale-price) ... sell-value (sell house-sale-profit-0 rmoc mib) ...] (- rent sell))) This way your individual functions become really simple, expressed in terms of their direct named inputs and outputs only, just like your PDF's equations. Your calculator function becomes the place where the web of interconnected values is realized through a sequence of intermediate values. You can easily test each individual function, just as you can now, only without the overhead and syntax of those extra maps (which carry a ton of extra values and obscure what's happening). Individual functions are less likely to recompute redundant values (I'm sure rent and sell both involve some common terms), and that avoidance doesn't involve jamming intermediate values into the argument map. More interestingly, this means you can build calculators for different things (maybe comparing the tax advantages of different mortgages and depreciation tricks...) by using the same functions. I don't know if that's possible with the map approach as you've written it. What you've done with the argument map approach is essentially to use a map as an object: the map is a bunch of fields, your derived-args function is a constructor (which sets up the derived members), and your individual functions are methods on that object. It's OO with a mask. Now, OO is sometimes the right way to do things, but if you really want to see whether a more functional approach has advantages in this situation, you should consider whether you can invert things a little. Just a thought. -- 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
Re: newbie question: Please help me stop creating constructors
I'm no Clojure guru myself, but one approach you may want to consider is nest all your auxiliary functions inside the main function, and use ordinary let-bindings the same way you've been trying to use global bindings: (defn sell-or-rent [{:keys [supplied-1 supplied-2]}] (let [derived-1 (+ 1 supplied-1) derived-2 (* 2 supplied-2)] (letfn [(f [x y z] ...) (g [x] ...)] ...))) This has the disadvantage of indenting all your helper functions much more than they would be otherwise, but it gets the job done without any messy global variables or thunks. If you want to expose more functions than just sell-or-rent, you could write some very OO-flavored code: ;; Define a function to create objects. (defn pseudo-constructor [{:keys [supplied-1 supplied-2]}] (let [member-var-1 (+ 1 supplied-1) member-var-2 (* 2 supplied-2)] (letfn [(private-method-1 [] priv1) (private-method-2 [] priv2)] {:public-method-1 (fn [x y z] pub1) :public-method-2 (fn [x y] pub2)}))) ;; Use the object. (let [obj (pseudo-constructor {:supplied-1 1 :supplied-2 2})] (println ((:public-method-1 obj) x y z)) (println ((:public-method-2 obj) x y))) --jw On Mon, Feb 15, 2010 at 11:24 AM, Yaron ygol...@gmail.com wrote: I am writing a calculator to figure out if I should sell or rent my home using Clojure. This is my first Clojure program so I'm about as wet behind the ears as it gets. So far everything is actually going really well (reminds me of the fun I had with Scheme in college) but for one thing. My calculator needs 30+ arguments from the user in order to run. Furthermore I have a bunch of secondary values that are derived from the arguments the user submits. So imagine the user submits a value A. I will have a value B whose definition will be something like (+ 1 A) (yes, more complex in reality, but you get the idea). If I were back in Java or C# I would define a class, submit A (and it's 29+ friends) in the constructor and then create a property on the class B. In Clojure I have taken a different approach. I first create (def *A* 3) where 3 is a completely bogus value I just made up. Then at run time I use bindings to re-bind A to the actual value the user passed in. But my problem is, what to do about B? I thought of doing something like (def *B* 3) and then in the binding passing in a function like (defn B-Gen [] (+ *A* 1)) to create a new binding to B but I quickly realized this would be a bug inducing nightmare. If I forget to include one of the derived values in the binding or put them in the wrong order then I would get the wrong value. So what I currently do is: (def *A* 3) ; A bogus value that will later be rebound (defn B [] (+ *A* 3)) The good news is, that this works and doesn't require any book keeping. The bad news is that it's ugly. If I want to do something trivial like divide B by 2 I have to call B as a function(/ (B) 2) instead of the more natural (/ B 2). And of course this approach is pretty unfortunate from a performance perspective as I'm constantly having to recalculate what are effectively static values. Yes, I could use memoization but many of these values are pretty trivial (usually just algebra equations) and I suspect the overhead of memoization exceeds the perf improvement. But in any case the whole approach of having to take what really are static values and turn them into functions feels really hacky. So my guess is that I'm thinking about this problem the wrong way. I'm stuck in my old imperative/OO constructor world. What's the right way to think about primary values that will be rebound (once) that then have dependent values that need to be recalculated when that rebinding happens? Thanks, Yaron -- 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.comclojure%2bunsubscr...@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 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
Re: newbie question: Please help me stop creating constructors
Way back when I was a wee lad I had been taught that a thunk is any function that takes no arguments. My definition for my derived values never took any arguments because they exclusively relied on global variables. For example: (defn months_actively_renting The number of months during the time we are in the rental business that we are either trying to rent the house out or have rented it out [] (* (+ *Months_To_Find_Tenant* *Months_In_Lease*) *Lease_Cycles*)) That's all I meant by the term thunk. On Feb 17, 10:20 pm, Richard Newman holyg...@gmail.com wrote: I'm just trying to figure out what the right pattern is because the fact that I'm forced to make the derived values into thunks feels really wrong but I honestly don't know what's right in the context of Clojure. I don't think you're using the term thunk correctly. A thunk is (usually) a no-argument function, typically used for things like delayed evaluation, and typically capturing some environment. E.g., (defn hello [thunk] (println Hello, (thunk))) (defn make-name-thunk [name] (fn [] name)) (let [n (make-name-thunk Jim)] (println Calling hello...) (hello n)) You are not making your derived values into thunks by this definition. Your derived values are just that: values, computed by functions. Compute them when you need them by invoking the appropriate functions with the appropriate arguments. Can you explain what you mean by thunk? -- 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
Re: newbie question: Please help me stop creating constructors
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
Re: newbie question: Please help me stop creating constructors
Richard Newman has with utmost patience (THANK YOU!), I believe, been trying to gently beat into my head from the start. No problem. Happy to help. 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. These things take time! Props for not giving up in disgust :) 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. Looks pretty good to me. I like your use of preconditions and the number of tests. I think your indentation is a little deep (I go for two spaces, myself), and I never use :Capital keywords, but otherwise great. You might be interested in the `are` macro to make your test code simpler: user= (doc are) - clojure.test/are ([argv expr args]) Macro Checks multiple assertions with a template expression. See clojure.template/do-template for an explanation of templates. Example: (are [x y] (= x y) 2 (+ 1 1) 4 (* 2 2)) Expands to: (do (is (= 2 (+ 1 1))) (is (= 4 (* 2 2 #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. That seems like a reasonable approach. 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. Pretty much! One suggestion: Rather than having two phases of derived args, and calling functions with arguments like: (total-house-depreciation args-and-mib) I'd save that step and adjust total-house-depreciation, year-sold, etc. to take an additional months-in-business argument: (defn total-house-depreciation The total amount of depreciation on the rental property taken over the period we were in business [args months-in-business] ...) Then you can change your derived-args function to: (defn derived-args [{:keys [months-to-find-tenant months-in-lease lease-cycles months-to- sell] :as args}] (assoc args :months-in-business (months-in-business months-to-find-tenant months-in-lease lease-cycles months-to-sell) :total-house-depreciation (total-house-depreciation args months- in-business) :year-sold (year-sold args months-in-business) :months-actively-renting (months-actively-renting months-to-find- tenant months-in-lease lease-cycles))) No lets at all. You'll see then that it's a small step from there to my suggested functional end game, which eliminates the passing of the args map altogether: derived-args would extract all the named arguments and pass just the specific ones to each function. No big deal, though; there are advantages to the map approach. Looking good! -R -- 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
Re: newbie question: Please help me stop creating constructors
Hi Yaron, Have you considered my example yet? It seems to fulfill your requirements. One of the primary use-cases of (binding) is to avoid bloating the parameter list of a group of functions. If my example does not satisfy your needs, then I think we may have all misunderstood what it is you're looking for. Something that you could do to get your point across is to post some Java code that illustrates the sort of abstraction that you're looking for. -Patrick -- 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
Re: newbie question: Please help me stop creating constructors
I did but it requires two levels of macro and that made me nervous. The problem is derived values. When defining a binding, near as I can tell, the values in the binding cannot see other values in the binding. In other words: (def *A* 10) (binding [*A* 3 B (+ foo 1)] B) Returns 11, not 4. So to use the macro I have to: (def *A* bogus_value) (def B bogus_value) (defmacro in-environment [env body] `(binding [*A* :A ..] (binding [B (+ *A* 1)...] ~...@body)) I think this would actually work. But it requires a bunch of accounting (all the bogus global defs) and introduces some worrisome ordering issues. For example, let's say I have a value C whose definition is (def C (+ B 1)). I can't define it using the previous macro. Because, again, bindings can't see each other. So now I'd have to write a macro that dynamically created a whole set of nested bindings. Which seems like a lot of work. In other words: (binding [*A* :A...] (binding [B (+ *A* 1)...] (binding [C (+ *B* 1)...] etc. And I can't use let (which does allow for internal visibility) because then other functions I call will bind to the global value not the let value. Yaron -- 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
Re: newbie question: Please help me stop creating constructors
I actually started off doing exactly what you suggested. The original version of my program used a map for the arguments and then used explicit arguments when the number of arguments fell to a reasonable level. For example, I started off with: (defn months_in_business The total number of months we will be in the business of renting out our home [Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell] (- (+ Months_To_Find_Tenant Months_In_Lease) (* Lease_Cycles) (+ Months_To_Sell))) Which got called as (months_in_business Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell) But this was a lot of typing every time I wanted to call the function. So I changed it to: (defn months_in_business The total number of months we will be in the business of renting out our home [:keys [Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell]] (- (+ Months_To_Find_Tenant Months_In_Lease) (* Lease_Cycles) (+ Months_To_Sell))) Which got called as (months_in_business bag_o_args) This at least meant less typing when calling the function but defining the function still required a bunch of typing. So eventually I just went to: (defn months_in_business The total number of months we will be in the business of renting out our home [] (- (+ *Months_To_Find_Tenant* *Months_In_Lease*) (* *Lease_Cycles*) (+ *Months_To_Sell*))) Which was called as: (months_in_business) At least there wasn't much typing involved but now I had a bunch of thunks running around. Which is what brought me to the group in the first place. It seems to me that there is a design principal here somewhere that says something like One shouldn't have to pass static values around as arguments to functions. But because there is nothing like an object context in Clojure this ended up meaning that derived values like months_in_business have to be thunks. Which I though was inelegant. If, on the other hand, I was implementing this in an object oriented language I would just say: class foo var A var B foo (bag_o_args) { A = (bag_o_args A) B = A+1 } And I would be done. No heaps of typing. No thunks. Just what looks to me like a nice simple solution. But I recognize that I'm just running home to mommy because my background is OO. That's why I came to the group in the first place. Since I know I'm blinded by my OO past I wanted to see if there was an approach to the problem in Clojure that was as easy and straight forward as what I would have done in an OO language. That having been said, defining a bunch of thunks isn't the worst thing in the world. But it is unfortunate from both a design and performance perspective. Yaron On Feb 16, 11:07 pm, Richard Newman holyg...@gmail.com wrote: It seems however that the consensus of the group based on what I've said so far is to pass around state in a structmap. Not necessarily a struct-map. Just a map. This is nice in that it makes each function completely self contained (e.g. no external references). It's unfortunate in that it now means that every single function needs this extra argument and every variable access either needs to use the :keys feature in the arguments or has to directly refer to the keys in the map. Not necessarily. At some point your functions should be fine-grained enough that they only take a couple of arguments. As soon as you drop below 6 or 7, where they're all mandatory, switch to ordinary function argument style. Wherever you call those functions should do the unpacking. E.g., (defn outer-1 [{:keys [foo bar baz noo]}] (let [interm (foo-bar foo bar) fiddle (frostrup baz noo)] (tweep interm fiddle))) After all, your house-sale-profit function should be expressed in terms of two arguments: (defn house-sale-profit [house-sale-price house-sale-expenses] ...) It doesn't care about the other 17. Another thing: that big entry point function is like a much tidier version of the Java constructor that you created with 19 arguments -- tidier in that you can use named keys or a map to identify the arguments. -- 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
Re: newbie question: Please help me stop creating constructors
I actually started off doing exactly what you suggested. The original version of my program used a map for the arguments and then used explicit arguments when the number of arguments fell to a reasonable level. For example, I started off with: (defn months_in_business The total number of months we will be in the business of renting out our home [Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell] (- (+ Months_To_Find_Tenant Months_In_Lease) (* Lease_Cycles) (+ Months_To_Sell))) Which got called as (months_in_business Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell) But this was a lot of typing every time I wanted to call the function. So I changed it to: (defn months_in_business The total number of months we will be in the business of renting out our home [:keys [Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell]] (- (+ Months_To_Find_Tenant Months_In_Lease) (* Lease_Cycles) (+ Months_To_Sell))) Which got called as (months_in_business bag_o_args) This at least meant less typing when calling the function but defining the function still required a bunch of typing. So eventually I just went to: (defn months_in_business The total number of months we will be in the business of renting out our home [] (- (+ *Months_To_Find_Tenant* *Months_In_Lease*) (* *Lease_Cycles*) (+ *Months_To_Sell*))) Which was called as: (months_in_business) At least there wasn't much typing involved but now I had a bunch of thunks running around. Which is what brought me to the group in the first place. It seems to me that there is a design principal here somewhere that says something like One shouldn't have to pass static values around as arguments to functions. But because there is nothing like an object context in Clojure this ended up meaning that derived values like months_in_business have to be thunks. Which I though was inelegant. If, on the other hand, I was implementing this in an object oriented language I would just say: class foo var A var B foo (bag_o_args) { A = (bag_o_args A) B = A+1 } And I would be done. No heaps of typing. No thunks. Just what looks to me like a nice simple solution. But I recognize that I'm just running home to mommy because my background is OO. That's why I came to the group in the first place. Since I know I'm blinded by my OO past I wanted to see if there was an approach to the problem in Clojure that was as easy and straight forward as what I would have done in an OO language. That having been said, defining a bunch of thunks isn't the worst thing in the world. But it is unfortunate from both a design and performance perspective. Yaron On Feb 16, 11:07 pm, Richard Newman holyg...@gmail.com wrote: It seems however that the consensus of the group based on what I've said so far is to pass around state in a structmap. Not necessarily a struct-map. Just a map. This is nice in that it makes each function completely self contained (e.g. no external references). It's unfortunate in that it now means that every single function needs this extra argument and every variable access either needs to use the :keys feature in the arguments or has to directly refer to the keys in the map. Not necessarily. At some point your functions should be fine-grained enough that they only take a couple of arguments. As soon as you drop below 6 or 7, where they're all mandatory, switch to ordinary function argument style. Wherever you call those functions should do the unpacking. E.g., (defn outer-1 [{:keys [foo bar baz noo]}] (let [interm (foo-bar foo bar) fiddle (frostrup baz noo)] (tweep interm fiddle))) After all, your house-sale-profit function should be expressed in terms of two arguments: (defn house-sale-profit [house-sale-price house-sale-expenses] ...) It doesn't care about the other 17. Another thing: that big entry point function is like a much tidier version of the Java constructor that you created with 19 arguments -- tidier in that you can use named keys or a map to identify the arguments. -- 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
Re: newbie question: Please help me stop creating constructors
Hi Yaron, You've slightly misunderstood my suggestion. I hope this will shed some reasoning on it: In OO, what you are effectively doing is this: The Object represents the environment under which you do your calculations. The environment object is created by your constructor. Once this environment has been created, you can use it to do calculations using foo.tax_deductible_expenses(1). My example is meant to capture this style of programming. (Whether this style is appropriate is up to you to decide.) The environment is represented by a map. You can write a function that creates an environment just like how you can write a constructor to create an environment object in Java. eg. new-environment( ... ) Once this environment has been created, you may use it to do calculations using (in-environment foo (tax-deductible-expenses 1)) The in-environment macro is not meant to contain any logic. It is solely meant to save you some typing. Hope that's more clear. -Patrick -- 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
Re: newbie question: Please help me stop creating constructors
I think it will help you get used to Clojure by spending some time to program in the most straight-forward way possible. Sometimes it's really helpful to just learn from a blank-slate instead of trying to find analogies to Java. -Patrick -- 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
Re: newbie question: Please help me stop creating constructors
You can combine let and binding like this to make this slightly more elegant: (let [a# 'expr involving *A* *B* and *C*'' b# 'expr involving *A* *B* and *C*'' c# 'expr involving *A* *B* and *C*''] (binding [*A* a# *B* b# *C* c#] ...)) Note the x# form which does an implicit gensym for you so you get unique names. This at least reduces it from n levels to two levels. It would be pretty easy to build a parallel-binding macro that did this for you. hth, Tom On Feb 17, 10:09 am, Yaron ygol...@gmail.com wrote: I did but it requires two levels of macro and that made me nervous. The problem is derived values. When defining a binding, near as I can tell, the values in the binding cannot see other values in the binding. In other words: (def *A* 10) (binding [*A* 3 B (+ foo 1)] B) Returns 11, not 4. So to use the macro I have to: (def *A* bogus_value) (def B bogus_value) (defmacro in-environment [env body] `(binding [*A* :A ..] (binding [B (+ *A* 1)...] �...@body)) I think this would actually work. But it requires a bunch of accounting (all the bogus global defs) and introduces some worrisome ordering issues. For example, let's say I have a value C whose definition is (def C (+ B 1)). I can't define it using the previous macro. Because, again, bindings can't see each other. So now I'd have to write a macro that dynamically created a whole set of nested bindings. Which seems like a lot of work. In other words: (binding [*A* :A...] (binding [B (+ *A* 1)...] (binding [C (+ *B* 1)...] etc. And I can't use let (which does allow for internal visibility) because then other functions I call will bind to the global value not the let value. Yaron -- 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
Re: newbie question: Please help me stop creating constructors
(defn months_in_business The total number of months we will be in the business of renting out our home [:keys [Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell]] (- (+ Months_To_Find_Tenant Months_In_Lease) (* Lease_Cycles) (+ Months_To_Sell))) - I have no idea why you want to type this much: (defn months-in-business [:keys [mtft mil lc mts] (- (+ mtft mil) (* lc) (+ mts)) But how do we know what these abbreviations mean while we develop our application? Write a couple of helper functions: (defn map-to-humane-repr [m] (let [ok (keys m) vs (vals m)] (zipmap (map mappings ok) vs))) (def *dummy* {:mtft 1, :mil 24, :lc 5, :mts 12}) (map-to-humane-repr *dummy*) - {Months to Sell 12, Lease Cycles 5, Months In Lease 24, Months To Find Tenant 1} -- 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
Re: newbie question: Please help me stop creating constructors
Hello, 2010/2/17 Yaron ygol...@gmail.com: I actually started off doing exactly what you suggested. The original version of my program used a map for the arguments and then used explicit arguments when the number of arguments fell to a reasonable level. For example, I started off with: (defn months_in_business The total number of months we will be in the business of renting out our home [Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell] (- (+ Months_To_Find_Tenant Months_In_Lease) (* Lease_Cycles) (+ Months_To_Sell))) Which got called as (months_in_business Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell) But this was a lot of typing every time I wanted to call the function. So I changed it to: (defn months_in_business The total number of months we will be in the business of renting out our home [:keys [Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell]] (- (+ Months_To_Find_Tenant Months_In_Lease) (* Lease_Cycles) (+ Months_To_Sell))) Which got called as (months_in_business bag_o_args) This at least meant less typing when calling the function but defining the function still required a bunch of typing. So eventually I just went to: (defn months_in_business The total number of months we will be in the business of renting out our home [] (- (+ *Months_To_Find_Tenant* *Months_In_Lease*) (* *Lease_Cycles*) (+ *Months_To_Sell*))) Which was called as: (months_in_business) At least there wasn't much typing involved but now I had a bunch of thunks running around. Which is what brought me to the group in the first place. It seems to me that there is a design principal here somewhere that says something like One shouldn't have to pass static values around as arguments to functions. But because there is nothing like an object context in Clojure this ended up meaning that derived values like months_in_business have to be thunks. Which I though was inelegant. If, on the other hand, I was implementing this in an object oriented language I would just say: class foo var A var B foo (bag_o_args) { A = (bag_o_args A) B = A+1 } I would like to try to help, but I first need to understand your (pseudo?) OO langage above. Could you detail it a little bit more ? And I would be done. No heaps of typing. No thunks. Just what looks to me like a nice simple solution. But I recognize that I'm just running home to mommy because my background is OO. That's why I came to the group in the first place. Since I know I'm blinded by my OO past I wanted to see if there was an approach to the problem in Clojure that was as easy and straight forward as what I would have done in an OO language. That having been said, defining a bunch of thunks isn't the worst thing in the world. But it is unfortunate from both a design and performance perspective. Yaron On Feb 16, 11:07 pm, Richard Newman holyg...@gmail.com wrote: It seems however that the consensus of the group based on what I've said so far is to pass around state in a structmap. Not necessarily a struct-map. Just a map. This is nice in that it makes each function completely self contained (e.g. no external references). It's unfortunate in that it now means that every single function needs this extra argument and every variable access either needs to use the :keys feature in the arguments or has to directly refer to the keys in the map. Not necessarily. At some point your functions should be fine-grained enough that they only take a couple of arguments. As soon as you drop below 6 or 7, where they're all mandatory, switch to ordinary function argument style. Wherever you call those functions should do the unpacking. E.g., (defn outer-1 [{:keys [foo bar baz noo]}] (let [interm (foo-bar foo bar) fiddle (frostrup baz noo)] (tweep interm fiddle))) After all, your house-sale-profit function should be expressed in terms of two arguments: (defn house-sale-profit [house-sale-price house-sale-expenses] ...) It doesn't care about the other 17. Another thing: that big entry point function is like a much tidier version of the Java constructor that you created with 19 arguments -- tidier in that you can use named keys or a map to identify the arguments. -- 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 post to this group, send email to clojure@googlegroups.com Note that
Re: newbie question: Please help me stop creating constructors
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
Re: newbie question: Please help me stop creating constructors
I think I see what you're saying. But honestly my goal isn't to replicate the OO experience. My goal is to replicate how easy OO made this specific scenario. In other words I want to use Clojure properly and trying to paste an OO framework on Clojure has got to be a major anti-pattern. I'm just trying to figure out what the right pattern is because the fact that I'm forced to make the derived values into thunks feels really wrong but I honestly don't know what's right in the context of Clojure. On Feb 17, 10:39 am, CuppoJava patrickli_2...@hotmail.com wrote: HiYaron, You've slightly misunderstood my suggestion. I hope this will shed some reasoning on it: In OO, what you are effectively doing is this: The Object represents the environment under which you do your calculations. The environment object is created by your constructor. Once this environment has been created, you can use it to do calculations using foo.tax_deductible_expenses(1). My example is meant to capture this style of programming. (Whether this style is appropriate is up to you to decide.) The environment is represented by a map. You can write a function that creates an environment just like how you can write a constructor to create an environment object in Java. eg. new-environment( ... ) Once this environment has been created, you may use it to do calculations using (in-environment foo (tax-deductible-expenses 1)) The in-environment macro is not meant to contain any logic. It is solely meant to save you some typing. Hope that's more clear. -Patrick -- 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
Re: newbie question: Please help me stop creating constructors
The reason for typing so much is maintainability. I'll have to come back to this code again and again over a period of years and there's no chance in heck I'll remember anything I did before. So I've learned that using clearer variable names, even with a little extra typing, is a price worth paying. On Feb 17, 10:46 am, David Nolen dnolen.li...@gmail.com wrote: (defn months_in_business The total number of months we will be in the business of renting out our home [:keys [Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell]] (- (+ Months_To_Find_Tenant Months_In_Lease) (* Lease_Cycles) (+ Months_To_Sell))) - I have no idea why you want to type this much: (defn months-in-business [:keys [mtft mil lc mts] (- (+ mtft mil) (* lc) (+ mts)) But how do we know what these abbreviations mean while we develop our application? Write a couple of helper functions: (defn map-to-humane-repr [m] (let [ok (keys m) vs (vals m)] (zipmap (map mappings ok) vs))) (def *dummy* {:mtft 1, :mil 24, :lc 5, :mts 12}) (map-to-humane-repr *dummy*) - {Months to Sell 12, Lease Cycles 5, Months In Lease 24, Months To Find Tenant 1} -- 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
Re: newbie question: Please help me stop creating constructors
That's actually quite a nifty use of the fact that code/data is the same in Clojure. But how do I test things out? In other words, how do I make sure that the expression defining a# is correct? Especially when any test has to itself be in the context of all the variables? But more to the point I think there is a difference between possible and desirable. You're giving me what I asked for, e.g. a way to achieve my goal of not having the derived values be thunks. But I can't help but think that I'm just approaching the whole problem in the wrong way in Clojure. That's why I posted http://www.goland.org/sellorrent.pdf. 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? On Feb 17, 10:48 am, Tom Faulhaber tomfaulha...@gmail.com wrote: You can combine let and binding like this to make this slightly more elegant: (let [a# 'expr involving *A* *B* and *C*'' b# 'expr involving *A* *B* and *C*'' c# 'expr involving *A* *B* and *C*''] (binding [*A* a# *B* b# *C* c#] ...)) Note the x# form which does an implicit gensym for you so you get unique names. This at least reduces it from n levels to two levels. It would be pretty easy to build a parallel-binding macro that did this for you. hth, Tom On Feb 17, 10:09 am,Yaronygol...@gmail.com wrote: I did but it requires two levels of macro and that made me nervous. The problem is derived values. When defining a binding, near as I can tell, the values in the binding cannot see other values in the binding. In other words: (def *A* 10) (binding [*A* 3 B (+ foo 1)] B) Returns 11, not 4. So to use the macro I have to: (def *A* bogus_value) (def B bogus_value) (defmacro in-environment [env body] `(binding [*A* :A ..] (binding [B (+ *A* 1)...] �...@body)) I think this would actually work. But it requires a bunch of accounting (all the bogus global defs) and introduces some worrisome ordering issues. For example, let's say I have a value C whose definition is (def C (+ B 1)). I can't define it using the previous macro. Because, again, bindings can't see each other. So now I'd have to write a macro that dynamically created a whole set of nested bindings. Which seems like a lot of work. In other words: (binding [*A* :A...] (binding [B (+ *A* 1)...] (binding [C (+ *B* 1)...] etc. And I can't use let (which does allow for internal visibility) because then other functions I call will bind to the global value not the let value. Yaron -- 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
Re: newbie question: Please help me stop creating constructors
I'm just trying to figure out what the right pattern is because the fact that I'm forced to make the derived values into thunks feels really wrong but I honestly don't know what's right in the context of Clojure. I don't think you're using the term thunk correctly. A thunk is (usually) a no-argument function, typically used for things like delayed evaluation, and typically capturing some environment. E.g., (defn hello [thunk] (println Hello, (thunk))) (defn make-name-thunk [name] (fn [] name)) (let [n (make-name-thunk Jim)] (println Calling hello...) (hello n)) You are not making your derived values into thunks by this definition. Your derived values are just that: values, computed by functions. Compute them when you need them by invoking the appropriate functions with the appropriate arguments. Can you explain what you mean by thunk? -- 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
Re: newbie question: Please help me stop creating constructors
Absolutely. I typed up an example in Scala. class RentOrSell(val Months_To_Find_Tenant: Int, val Months_In_Lease: Int, val Lease_Cycles: Int, val Months_To_Sell: Int) { val months_in_business: Int = ((Months_To_Find_Tenant + Months_In_Lease) * Lease_Cycles) + Months_To_Sell } When I create a class instance I pass in the user defined variables (I only used 4 in this example). Those values are then bound as invariant values and used to create months_in_business which is itself an invariant value (e.g. bound at class creation time and then immutable). This is the effect I was expecting. That I could define both the user supplied values and the derived values as immutable values. Instead I had to create thunks for the derived values for the reasons previously described. But again I'm completely open to the idea that I'm just going about this all wrong. I have spent more years of my life than I care to remember writing OO code so I have no doubt I'm relying on instincts that just don't apply here. Ideally I'd love to figure out how to properly write a program that implements http://www.goland.org/sellorrent.pdf in Clojure rather than beat Clojure into looking like what I'm used to from my OO days. Put another way, I speak Clojure with a really thick OO accent and I'd like to learn better how to speak it like a native. :) Yaron On Feb 17, 11:53 am, Laurent PETIT laurent.pe...@gmail.com wrote: Hello, 2010/2/17Yaronygol...@gmail.com: I actually started off doing exactly what you suggested. The original version of my program used a map for the arguments and then used explicit arguments when the number of arguments fell to a reasonable level. For example, I started off with: (defn months_in_business The total number of months we will be in the business of renting out our home [Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell] (- (+ Months_To_Find_Tenant Months_In_Lease) (* Lease_Cycles) (+ Months_To_Sell))) Which got called as (months_in_business Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell) But this was a lot of typing every time I wanted to call the function. So I changed it to: (defn months_in_business The total number of months we will be in the business of renting out our home [:keys [Months_To_Find_Tenant Months_In_Lease Lease_Cycles Months_To_Sell]] (- (+ Months_To_Find_Tenant Months_In_Lease) (* Lease_Cycles) (+ Months_To_Sell))) Which got called as (months_in_business bag_o_args) This at least meant less typing when calling the function but defining the function still required a bunch of typing. So eventually I just went to: (defn months_in_business The total number of months we will be in the business of renting out our home [] (- (+ *Months_To_Find_Tenant* *Months_In_Lease*) (* *Lease_Cycles*) (+ *Months_To_Sell*))) Which was called as: (months_in_business) At least there wasn't much typing involved but now I had a bunch of thunks running around. Which is what brought me to the group in the first place. It seems to me that there is a design principal here somewhere that says something like One shouldn't have to pass static values around as arguments to functions. But because there is nothing like an object context in Clojure this ended up meaning that derived values like months_in_business have to be thunks. Which I though was inelegant. If, on the other hand, I was implementing this in an object oriented language I would just say: class foo var A var B foo (bag_o_args) { A = (bag_o_args A) B = A+1 } I would like to try to help, but I first need to understand your (pseudo?) OO langage above. Could you detail it a little bit more ? And I would be done. No heaps of typing. No thunks. Just what looks to me like a nice simple solution. But I recognize that I'm just running home to mommy because my background is OO. That's why I came to the group in the first place. Since I know I'm blinded by my OO past I wanted to see if there was an approach to the problem in Clojure that was as easy and straight forward as what I would have done in an OO language. That having been said, defining a bunch of thunks isn't the worst thing in the world. But it is unfortunate from both a design and performance perspective. Yaron On Feb 16, 11:07 pm, Richard Newman holyg...@gmail.com wrote: It seems however that the consensus of the group based on what I've said so far is to pass around state in a structmap. Not necessarily a struct-map. Just a map. This is nice in that it makes each function completely self contained (e.g. no external references). It's unfortunate in that it now means that every single function needs this extra argument and every variable access either needs to use the :keys feature in the arguments or
Re: newbie question: Please help me stop creating constructors
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
Re: newbie question: Please help me stop creating constructors
Sean and Richard perhaps I can address both of your mails in a single go. Here is an example of one of the functions from my calculator: (defn tax_deductible_expenses The total expenses incurred in business month m that are deductible from federal income tax [m] (let [prepHouse (inflate *Prep_House_0* m) fixedMonthlyCost (if (= m (months_in_business)) 0 (fixed_monthly_cost m))] (condp = (house_state m) :ForLease (+ fixedMonthlyCost (if (= (month_in_rental_cycle m) 0) prepHouse 0)) :Leased (+ fixedMonthlyCost (* (rental_income m) (+ *Management_Fee* (if (= (month_in_rental_cycle m) *Months_To_Find_Tenant*) *Tenant_Finding_Fee* 0 :ForSale (+ fixedMonthlyCost (if (= m (months_actively_renting)) prepHouse 0)) :Sold (house_sales_expenses m Right now the function takes a single argument, m which is the month that tax deductible expenses are being calculated for. All the other values it needs are constants (e.g. either values provided at the start by the user or derived values). Now please look at a test I wrote to make sure the function does what I think it does: (deftest tax_deductible_expenses_basic (binding [*Months_To_Find_Tenant* 5 *Months_In_Lease* 5 *Lease_Cycles* 1 *House_Sales_Price_0* 300 *Monthly_Inflation_Rate* 0.002 *Buying_Agent_Fee_Type* :Percentage *Buying_Agent_Fee_Number* 0.05 *Selling_Agent_Fee_Type* :FlatFee *Selling_Agent_Fee_Number* 1000 *Other_Sales_Fee_0* 100 *Excise_Tax* 0.5 *Original_Loan_Amount* 1 *Monthly_Loan_Interest* (/ 0.05 12) *Months_In_Loan* (* 10 12) *Loan_Month_At_Start* 3 *Prep_House_0* 100 *Management_Fee* 2 *Tenant_Finding_Fee* 0.5 *Months_To_Sell* 3] (is (= (tax_deductible_expenses 0) (+ (fixed_monthly_cost 0) 100))) (is (= (tax_deductible_expenses 1) (fixed_monthly_cost 1))) (is (= (tax_deductible_expenses 5) (+ (fixed_monthly_cost 5) (* (rental_income 5) 2.5 (is (= (tax_deductible_expenses 7) (+ (fixed_monthly_cost 7) (* (rental_income 7) 2 (is (= (tax_deductible_expenses 10) (+ (fixed_monthly_cost 10) (inflate 100 10 (is (= (tax_deductible_expenses 12) (fixed_monthly_cost 12))) (is (= (tax_deductible_expenses 13) (house_sales_expenses 13) For the method tax_deductible_expenses to run it ends up requiring 19 user defined values. That's a whole lot of arguments to pass into a function. Obviously I could wrap them up in a StructMap but then I get expressions like (+ 1 (args :B)) which doesn't seem much better than (+1 (B)). The issue I'm really trying to put my finger on is - these arguments really and truly are 'constants' within the context of the calculator. But they are constants whose values are not known as compile time but rather are known at run time. Does Clojure have a way to express a 'late bound' constant or is the 'right' solution to pass around 19+ arguments to functions or passing around StructMaps or making everything into thunks? Thanks! Yaron On Feb 15, 1:33 pm, Richard Newman holyg...@gmail.com wrote: So imagine the user submits a value A. I will have a value B whose definition will be something like (+ 1 A) (yes, more complex in reality, but you get the idea). In Java, everything's an object, so you go about this by defining some class. All of its private members, its constructors, and its accessors are there to support one thing: should I sell or rent my home? That is, rather than saying something like: should-i-sell given that: current-home-price = 100,000 current-interest-rate = 5.2% ... you say HomeCalculator c = new HomeCalculator(10, 5.2, ...); boolean shouldSell = c.shouldSell(); and the logic is tied up in the shouldSell method definition. When someone calls .setA(...), you have to recompute B, or you have to make sure that B is dynamically computed in .getB(). That's not how you do things in a functional programming language. You don't define global variables B and A. Define functions that compute things; thread them together; and then push your values in the top. Start from the bottom up and the top down together; build a tree of functions that compute what you want. For example, you might think ah, I need to figure out my monthly payment on my mortgage. That's a function of the initial principal, the term, and the rate: (defn monthly-payment [principal term-in-months interest-rate] ...) Then you want to figure out how much more or less you'll pay, assuming a growth in rents of a certain percentage, over some number of months spent living in the house. Let's start by computing a sequence of rents, increasing over time: (defn monthly-rent [starting-value monthly-increase] (lazy-seq starting-value
Re: newbie question: Please help me stop creating constructors
On Feb 16, 8:27 pm, Yaron ygol...@gmail.com wrote: Sean and Richard perhaps I can address both of your mails in a single go. Here is an example of one of the functions from my calculator: (defn tax_deductible_expenses The total expenses incurred in business month m that are deductible from federal income tax [m] (let [prepHouse (inflate *Prep_House_0* m) fixedMonthlyCost (if (= m (months_in_business)) 0 (fixed_monthly_cost m))] (condp = (house_state m) :ForLease (+ fixedMonthlyCost (if (= (month_in_rental_cycle m) 0) prepHouse 0)) :Leased (+ fixedMonthlyCost (* (rental_income m) (+ *Management_Fee* (if (= (month_in_rental_cycle m) *Months_To_Find_Tenant*) *Tenant_Finding_Fee* 0 :ForSale (+ fixedMonthlyCost (if (= m (months_actively_renting)) prepHouse 0)) :Sold (house_sales_expenses m Right now the function takes a single argument, m which is the month that tax deductible expenses are being calculated for. All the other values it needs are constants (e.g. either values provided at the start by the user or derived values). First, a style nitpick: use foo-bar instead of fooBar or foo_bar secondly, yes, you really should pass in a map of all the relevant information. It might help to split up your calculator into multiple functions, each of which deals with only part of the map. It might even make sense to group the arguments a bit and pass in multiple maps, or just some args outside of a map. The ideal is that a function depends only on its parameters. Having many rebindable globals is certainly *not* the way to go. :) For derived values, you might be able to use let-bound locals. Now please look at a test I wrote to make sure the function does what I think it does: (deftest tax_deductible_expenses_basic (binding [*Months_To_Find_Tenant* 5 *Months_In_Lease* 5 *Lease_Cycles* 1 *House_Sales_Price_0* 300 *Monthly_Inflation_Rate* 0.002 *Buying_Agent_Fee_Type* :Percentage *Buying_Agent_Fee_Number* 0.05 *Selling_Agent_Fee_Type* :FlatFee *Selling_Agent_Fee_Number* 1000 *Other_Sales_Fee_0* 100 *Excise_Tax* 0.5 *Original_Loan_Amount* 1 *Monthly_Loan_Interest* (/ 0.05 12) *Months_In_Loan* (* 10 12) *Loan_Month_At_Start* 3 *Prep_House_0* 100 *Management_Fee* 2 *Tenant_Finding_Fee* 0.5 *Months_To_Sell* 3] (is (= (tax_deductible_expenses 0) (+ (fixed_monthly_cost 0) 100))) (is (= (tax_deductible_expenses 1) (fixed_monthly_cost 1))) (is (= (tax_deductible_expenses 5) (+ (fixed_monthly_cost 5) (* (rental_income 5) 2.5 (is (= (tax_deductible_expenses 7) (+ (fixed_monthly_cost 7) (* (rental_income 7) 2 (is (= (tax_deductible_expenses 10) (+ (fixed_monthly_cost 10) (inflate 100 10 (is (= (tax_deductible_expenses 12) (fixed_monthly_cost 12))) (is (= (tax_deductible_expenses 13) (house_sales_expenses 13) For the method tax_deductible_expenses to run it ends up requiring 19 user defined values. That's a whole lot of arguments to pass into a function. Obviously I could wrap them up in a StructMap but then I get expressions like (+ 1 (args :B)) which doesn't seem much better than (+1 (B)). The issue I'm really trying to put my finger on is - these arguments really and truly are 'constants' within the context of the calculator. But they are constants whose values are not known as compile time but rather are known at run time. Does Clojure have a way to express a 'late bound' constant or is the 'right' solution to pass around 19+ arguments to functions or passing around StructMaps or making everything into thunks? If you're passing 19 arguments to a function, it's most likely doing too much. See if you can split up the logic somewhat. -- 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
Re: newbie question: Please help me stop creating constructors
What do you think of the following style? (defmacro in-environment [env body] `(binding [*months-to-find-tenant* (:months-to-find-tenant env) *months-in-lease* (:months-in-lease env) *lease-cycles* (:lease-cycles env) etc...] ~...@body)) So env is a map that would contain the appropriate constants that you need. Whenever you need them you can access them like this: (in-environment env (tax-deductible-expenses 1)) That being said, I am not sure if that's the way I would do it. But I haven't seen the rest of your program and it's possible that this is perfectly justified. -Patrick -- 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
Re: newbie question: Please help me stop creating constructors
For the method tax_deductible_expenses to run it ends up requiring 19 user defined values. That's a whole lot of arguments to pass into a function. Obviously I could wrap them up in a StructMap but then I get expressions like (+ 1 (args :B)) which doesn't seem much better than (+1 (B)). Pass them in as a map, and destructure at the start of the function: (defn tax-deductible-expenses [{:keys [management-fee tenant-finding-fee ...]}] ...) The issue I'm really trying to put my finger on is - these arguments really and truly are 'constants' within the context of the calculator. But they are constants whose values are not known as compile time but rather are known at run time. That they're constant does not mean that you shouldn't pass them as arguments to your functions. Most values obtained from users or config files are such run-time constants. Heck, many values in most programs are -- HTTP listener port, log file location, etc. You still invoke your HTTP server with a :port argument. Indeed, the more fixed values you have, the less likely it is that you should define a var for each. Maybe one var containing a map, but I'd still pass the map around rather than having each function implicitly refer to it. It makes testing easier. Does Clojure have a way to express a 'late bound' constant or is the 'right' solution to pass around 19+ arguments to functions or passing around StructMaps or making everything into thunks? The reason you pass them around as arguments is so that the behavior of your functions is precisely determined *only* by its arguments -- they are pure. That means that you can memoize them, easily write tests for them, have them work correctly when part of a lazy sequence (which will often be evaluated outside the scope of your bindings), etc. For example: how would you compare the tax-deductible-expenses of two clients? You'd need to invoke the function twice, with a huge nest of bindings around each call. Much better would be to store the appropriate values in two maps, then say ( (tax-deductible-expenses 0 john-data) (tax-deductible-expenses 0 bill-data)) -R -- 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
Re: newbie question: Please help me stop creating constructors
I have posted a file (http://www.goland.org/sellorrent.pdf) which explains the math behind the calculator. The file gives all the algebra needed to implement the calculator. At the moment I'm just taking the boneheaded approach and implementing all the logic in Clojure as more or less a one to one mapping of the functions in the PDF file. Please, please, please, keep in mind that the linked article is a very rough, rough draft. It is not ready for prime time. I am only sharing it so that you can see what I'm trying to implement and hopefully guide me to the right way to implement it. It seems however that the consensus of the group based on what I've said so far is to pass around state in a structmap. This is nice in that it makes each function completely self contained (e.g. no external references). It's unfortunate in that it now means that every single function needs this extra argument and every variable access either needs to use the :keys feature in the arguments or has to directly refer to the keys in the map. I really wish there was a way for me to just declare a context, define a bunch of statics and then define all my methods inside of that context. But it doesn't seem like this is the clojure way of handling the problem. Where as many aspects of functional programming make a ton of sense to me having to carry a map around everywhere doesn't seem like an advantage. But I'm probably just missing something. Yaron On Feb 16, 1:20 pm, Richard Newman holyg...@gmail.com wrote: For the method tax_deductible_expenses to run it ends up requiring 19 user defined values. That's a whole lot of arguments to pass into a function. Obviously I could wrap them up in a StructMap but then I get expressions like (+ 1 (args :B)) which doesn't seem much better than (+1 (B)). Pass them in as a map, and destructure at the start of the function: (defn tax-deductible-expenses [{:keys [management-fee tenant-finding-fee ...]}] ...) The issue I'm really trying to put my finger on is - these arguments really and truly are 'constants' within the context of the calculator. But they are constants whose values are not known as compile time but rather are known at run time. That they're constant does not mean that you shouldn't pass them as arguments to your functions. Most values obtained from users or config files are such run-time constants. Heck, many values in most programs are -- HTTP listener port, log file location, etc. You still invoke your HTTP server with a :port argument. Indeed, the more fixed values you have, the less likely it is that you should define a var for each. Maybe one var containing a map, but I'd still pass the map around rather than having each function implicitly refer to it. It makes testing easier. Does Clojure have a way to express a 'late bound' constant or is the 'right' solution to pass around 19+ arguments to functions or passing around StructMaps or making everything into thunks? The reason you pass them around as arguments is so that the behavior of your functions is precisely determined *only* by its arguments -- they are pure. That means that you can memoize them, easily write tests for them, have them work correctly when part of a lazy sequence (which will often be evaluated outside the scope of your bindings), etc. For example: how would you compare the tax-deductible-expenses of two clients? You'd need to invoke the function twice, with a huge nest of bindings around each call. Much better would be to store the appropriate values in two maps, then say ( (tax-deductible-expenses 0 john-data) (tax-deductible-expenses 0 bill-data)) -R -- 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
Re: newbie question: Please help me stop creating constructors
It seems however that the consensus of the group based on what I've said so far is to pass around state in a structmap. Not necessarily a struct-map. Just a map. This is nice in that it makes each function completely self contained (e.g. no external references). It's unfortunate in that it now means that every single function needs this extra argument and every variable access either needs to use the :keys feature in the arguments or has to directly refer to the keys in the map. Not necessarily. At some point your functions should be fine-grained enough that they only take a couple of arguments. As soon as you drop below 6 or 7, where they're all mandatory, switch to ordinary function argument style. Wherever you call those functions should do the unpacking. E.g., (defn outer-1 [{:keys [foo bar baz noo]}] (let [interm (foo-bar foo bar) fiddle (frostrup baz noo)] (tweep interm fiddle))) After all, your house-sale-profit function should be expressed in terms of two arguments: (defn house-sale-profit [house-sale-price house-sale-expenses] ...) It doesn't care about the other 17. Another thing: that big entry point function is like a much tidier version of the Java constructor that you created with 19 arguments -- tidier in that you can use named keys or a map to identify the arguments. -- 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
Re: newbie question: Please help me stop creating constructors
Let's start with what you've got. Could you post some of your code on github, or something similar? That would make it easier to help you along. Sean On Feb 15, 12:24 pm, Yaron ygol...@gmail.com wrote: I am writing a calculator to figure out if I should sell or rent my home using Clojure. This is my first Clojure program so I'm about as wet behind the ears as it gets. So far everything is actually going really well (reminds me of the fun I had with Scheme in college) but for one thing. My calculator needs 30+ arguments from the user in order to run. Furthermore I have a bunch of secondary values that are derived from the arguments the user submits. So imagine the user submits a value A. I will have a value B whose definition will be something like (+ 1 A) (yes, more complex in reality, but you get the idea). If I were back in Java or C# I would define a class, submit A (and it's 29+ friends) in the constructor and then create a property on the class B. In Clojure I have taken a different approach. I first create (def *A* 3) where 3 is a completely bogus value I just made up. Then at run time I use bindings to re-bind A to the actual value the user passed in. But my problem is, what to do about B? I thought of doing something like (def *B* 3) and then in the binding passing in a function like (defn B-Gen [] (+ *A* 1)) to create a new binding to B but I quickly realized this would be a bug inducing nightmare. If I forget to include one of the derived values in the binding or put them in the wrong order then I would get the wrong value. So what I currently do is: (def *A* 3) ; A bogus value that will later be rebound (defn B [] (+ *A* 3)) The good news is, that this works and doesn't require any book keeping. The bad news is that it's ugly. If I want to do something trivial like divide B by 2 I have to call B as a function(/ (B) 2) instead of the more natural (/ B 2). And of course this approach is pretty unfortunate from a performance perspective as I'm constantly having to recalculate what are effectively static values. Yes, I could use memoization but many of these values are pretty trivial (usually just algebra equations) and I suspect the overhead of memoization exceeds the perf improvement. But in any case the whole approach of having to take what really are static values and turn them into functions feels really hacky. So my guess is that I'm thinking about this problem the wrong way. I'm stuck in my old imperative/OO constructor world. What's the right way to think about primary values that will be rebound (once) that then have dependent values that need to be recalculated when that rebinding happens? Thanks, Yaron -- 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
Re: newbie question: Please help me stop creating constructors
So imagine the user submits a value A. I will have a value B whose definition will be something like (+ 1 A) (yes, more complex in reality, but you get the idea). In Java, everything's an object, so you go about this by defining some class. All of its private members, its constructors, and its accessors are there to support one thing: should I sell or rent my home? That is, rather than saying something like: should-i-sell given that: current-home-price = 100,000 current-interest-rate = 5.2% ... you say HomeCalculator c = new HomeCalculator(10, 5.2, ...); boolean shouldSell = c.shouldSell(); and the logic is tied up in the shouldSell method definition. When someone calls .setA(...), you have to recompute B, or you have to make sure that B is dynamically computed in .getB(). That's not how you do things in a functional programming language. You don't define global variables B and A. Define functions that compute things; thread them together; and then push your values in the top. Start from the bottom up and the top down together; build a tree of functions that compute what you want. For example, you might think ah, I need to figure out my monthly payment on my mortgage. That's a function of the initial principal, the term, and the rate: (defn monthly-payment [principal term-in-months interest-rate] ...) Then you want to figure out how much more or less you'll pay, assuming a growth in rents of a certain percentage, over some number of months spent living in the house. Let's start by computing a sequence of rents, increasing over time: (defn monthly-rent [starting-value monthly-increase] (lazy-seq starting-value (monthly-rent (* (+ 1 monthly-percentage-increase) starting- value) monthly-increase))) then we want to weigh these against each other: (defn rent-cost-over-time [starting-value monthly-increase months] (reduce + (take months (monthly-rent starting-value monthly- increase))) (defn mortgage-cost-over-time [principal term-in-months interest-rate months] (...)) You get the idea: you're building a library of *pure* functions, each of which does one thing to some inputs, and might rely on the others. Now you're ready to phrase your question as a function: (defn should-i-sell [initial-mortgage-principal monthly-interest-rate months-already-paid-into-house ...] ) If you want to use keywords to denote named arguments, you can do that: (defn should-i-sell [ args] (let [{:keys [initial-mortgage-principal ...]} (apply hash-map args)] ...) No bindings. No global definitions. No redefinition. No state. User input comes in to your function and is passed through other functions. Eventually you get a value. If the user input changes, re-run the function. Dataflow programming is overkill for what you're doing. You don't have primary values and dependent values: you have function inputs, and functions that compute values from inputs. Hope that helps... -R -- 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