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.com<clojure%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