newbie question: Please help me stop creating constructors

35 views
Skip to first unread message

Yaron

unread,
Feb 15, 2010, 12:24:58 PM2/15/10
to Clojure
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

Sean Devlin

unread,
Feb 15, 2010, 4:16:20 PM2/15/10
to Clojure
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

Richard Newman

unread,
Feb 15, 2010, 4:33:33 PM2/15/10
to clo...@googlegroups.com
> 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(100000, 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

Yaron

unread,
Feb 16, 2010, 1:27:13 PM2/16/10
to Clojure
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* 10000
*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

Jarkko Oranen

unread,
Feb 16, 2010, 4:18:43 PM2/16/10
to Clojure

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.

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.

CuppoJava

unread,
Feb 16, 2010, 6:00:33 PM2/16/10
to Clojure
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

Richard Newman

unread,
Feb 16, 2010, 4:20:17 PM2/16/10
to clo...@googlegroups.com
> 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


Yaron

unread,
Feb 17, 2010, 1:14:49 AM2/17/10
to Clojure
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

Richard Newman

unread,
Feb 17, 2010, 2:07:48 AM2/17/10
to clo...@googlegroups.com
> 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.

CuppoJava

unread,
Feb 17, 2010, 11:36:35 AM2/17/10
to Clojure
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

Yaron

unread,
Feb 17, 2010, 1:09:50 PM2/17/10
to Clojure
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

Yaron

unread,
Feb 17, 2010, 1:25:42 PM2/17/10
to Clojure
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

Yaron

unread,
Feb 17, 2010, 1:25:51 PM2/17/10
to Clojure

Yaron

CuppoJava

unread,
Feb 17, 2010, 1:39:26 PM2/17/10
to Clojure
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

CuppoJava

unread,
Feb 17, 2010, 1:43:37 PM2/17/10
to Clojure
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

David Nolen

unread,
Feb 17, 2010, 1:46:11 PM2/17/10
to clo...@googlegroups.com
(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}

Tom Faulhaber

unread,
Feb 17, 2010, 1:48:58 PM2/17/10
to Clojure
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

Laurent PETIT

unread,
Feb 17, 2010, 2:53:43 PM2/17/10
to clo...@googlegroups.com
Hello,

2010/2/17 Yaron <ygo...@gmail.com>:

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 ?

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@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+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

Michał Marczyk

unread,
Feb 17, 2010, 10:43:45 PM2/17/10
to clo...@googlegroups.com
I must say that I find Richard's suggestions to be very reasonable,
but I'd like to add my own take... This is meant as a step-by-step
account of my thinking process, so it starts out with a statement of
the basics. Skim & skip if you prefer.

The problem to be solved is basically a huge calculation. When written
out -- for the purpose of defining the problem -- in the usual
mathematical notation, it turns out to depend on multiple free
variables (inflation rate, interest on the mortgage etc.); then
there's a bunch of named parameters / dependent variables whose values
are derived from those free variables.

So, the natural thing to do is what you do in that .pdf you posted:
you break it down into a bunch of equations defining the dependent
variables in the above in terms of the free variables and / or
previously defined dependent variables plus one inequality of the
form, say, rent-profit <= sale-profit, whose truth or falsity is to be
established.

Now, an imperative programme to calculate whether rent-profit does or
does not exceed sale-profit would proceed as follows:

free-variable-1 = some-value-1
free-variable-2 = some-value-2
...
dependent-variable-1 = some-function-of(free-variable-k,
free-variable-l, free-variable-n)
...
answer = rent-profit-function(...some-arguments...) <=
sale-profit-function(...some-arguments...)

A functional programme, on the other hand, would contain no section to
correspond to the free-variable-n assignments at all. Then in place of
all the dependent-variable-m assignments it would contain function
definitions:

(defn calculate-dependent-variable-1 [free-var-k, free-var-l ...]
...)

When you start composing those, you do things like

(defn calculate-problematic-quantity [...all free vars needed in side...]
(let [dep-var-1 (calculate-dependent-variable-1 ...the arguments...)
dep-var-2 (calculate-dependent-variable-2 ...the arguments...)
...]
...combine the free-vars received as arguments
with the dep-vars calculated in the bindings portion of the
let form to produce the return value...))

Feel free to receive dependent variables as arguments if you're likely
to have multiple functions depend on them in some way:

(defn f1 [dep-var-1 ...] ...)
(defn f2 [dep-var-1 ...] ...)
(defn function-using-f1-f2 [...args...]
(let [dep-var-1 (calculate-dependent-variable-1 ...args...)
f1-val (f1 dep-var-1 ...)
f2-val (f2 dep-var-1 ...)
...))

Then once you do have all the building blocks in place, you'd write
one monster entry function taking some values for the free variables
-- perhaps in the form of a map -- and have it call the
building-block-functions, perhaps using the sequential binding
facitility of the let special form to name intermediate values for use
in further computational steps.

This process strikes me as incredibly similar to what you would do if
you were to solve the equations by hand: you break them down into
well-defined intermediate steps, write down recipes defining the exact
nature of those steps, then write down formulae combining the results
of those intermediate steps. You strive to reduce the number of free
variables any single equation depends on, preferring to break down
huge equations into smaller ones which depend on parameters defined by
further small equations. Etc.

In Haskell you can even write the "main equations" on top, followed by
the helper equations lower down, possibly limiting the scope of the
latter:

calculateFoo x y z = fooComponent1 + fooComponent2
where
fooComponent1 = (some expression in x, y, z)
fooComponent2 = (some expression in x, y, z)

In Clojure you'd use a let form for that, which may be a blessing or a
curse both syntactically (the issue of what you put on the top) and
semantically (because "where" and "let" bindings are mutually
recursive in Haskell). The basic idea stays the same, though, with
Haskell's syntax perhaps making it slightly more obvious how the
Haskell functions involved are almost direct transliterations of the
mathematical, purely declarative statements of the nature of the
calculational subproblems. That syntax is something you'd actually
have to learn the (considerable) quirks of, so some find the Lisp
syntax-less approach ultimately more manageable (myself included).

Anyway, I'd say that your project is the perfect dream use case for
functional programming... I wonder if I've managed to expose some of
my reasons for feeling this way? :-)

An additional note: given the purpose of the calculations involved, I
guess you'll want to be well-assured of the correctness of the result.
Using maps to pass around named values may help with that; I'd even go
as far as using assertions and / or preconditions to make sure that
each function does receive all the values it expects in its argument
map.

What I *would not* do, however, is to mass around one huge map all the
time; I'd still only give each function the exact arguments it must
receive, putting them in a map only to avoid silly bugs like (f
interest inflation) instead of (f inflation interest). The latter may
be hard to catch; a misdefined map like {:interest inflation
:inflation interest} is easy to catch in code review (and not very
likely to be written in the first place).

All best,
Michał

Yaron

unread,
Feb 18, 2010, 1:14:26 AM2/18/10
to Clojure
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,

Yaron

unread,
Feb 18, 2010, 1:15:28 AM2/18/10
to Clojure
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.

Yaron

unread,
Feb 18, 2010, 1:19:10 AM2/18/10
to Clojure
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
>

Richard Newman

unread,
Feb 18, 2010, 1:20:56 AM2/18/10
to clo...@googlegroups.com
> 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"?

Yaron

unread,
Feb 18, 2010, 1:26:43 AM2/18/10
to Clojure
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/17Yaron<ygol...@gmail.com>:

Richard Newman

unread,
Feb 18, 2010, 1:36:45 AM2/18/10
to clo...@googlegroups.com
> 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.

John Williams

unread,
Feb 18, 2010, 7:27:32 PM2/18/10
to clo...@googlegroups.com
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

Yaron

unread,
Feb 19, 2010, 1:06:40 AM2/19/10
to Clojure
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.

Yaron

unread,
Feb 19, 2010, 1:39:17 AM2/19/10
to Clojure
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

Richard Newman

unread,
Feb 19, 2010, 2:25:22 AM2/19/10
to clo...@googlegroups.com
> 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

Yaron

unread,
Feb 19, 2010, 12:30:44 PM2/19/10
to Clojure
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"?

> > clojure+u...@googlegroups.com<clojure%2Bunsu...@googlegroups.com>

John Williams

unread,
Feb 19, 2010, 9:09:23 PM2/19/10
to clo...@googlegroups.com
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.

Yaron

unread,
Feb 20, 2010, 12:49:33 AM2/20/10
to Clojure

> 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

Richard Newman

unread,
Feb 20, 2010, 1:15:25 AM2/20/10
to clo...@googlegroups.com
> 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.

Yaron

unread,
Feb 28, 2010, 9:36:52 PM2/28/10
to Clojure
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

Richard Newman

unread,
Mar 1, 2010, 2:55:18 AM3/1/10
to clo...@googlegroups.com
> 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 same technique in, say, Pascal: define a
bunch of functions, and use a bunch of local variables in the calling
function to store intermediate values; gradually work towards the
final answer. Clojure can make this simpler (using macros, higher-
order functions, partial evaluation, and so on), but it doesn't really
change the nature of the work.

(Of course, traditional imperative languages would have given you a
mutable global chalkboard on which to play concurrency Hangman, but
for a one-time calculator that's no real problem.)

Sure, if you had a hundred thousand intermediate results, and a
thousand inputs, you wouldn't do it this way... but if that were true,
I'd be advising you to use a tool which is more suited, such as a
spreadsheet or some other dataflow system.

HTH.

-R

Laurent PETIT

unread,
Mar 1, 2010, 4:23:14 AM3/1/10
to clo...@googlegroups.com
2010/2/20 Yaron <ygo...@gmail.com>


> 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.

Hi, note that eclipse does not have proper clojure indentation yet (and, btw, didn't claim so).
What you're seeing just the out-of-the-box text file indentation stuff which indents text of a new line in the same column as non blank text of the previous line.
Nothing really exciting yet. :)


Jarkko Oranen

unread,
Mar 1, 2010, 4:47:38 AM3/1/10
to Clojure

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.

Andrzej

unread,
Mar 1, 2010, 5:19:13 AM3/1/10
to clo...@googlegroups.com
On Thu, Feb 18, 2010 at 3:36 PM, Richard Newman <holy...@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

Richard Newman

unread,
Mar 1, 2010, 9:45:57 AM3/1/10
to clo...@googlegroups.com
> 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.

Johnny Kwan

unread,
Mar 1, 2010, 9:58:03 AM3/1/10
to clo...@googlegroups.com
Hi,

This is a solver, which is standard functionality in a spreadsheet.
Obviously, writing a solver is much larger on scope than writing a
formula calculator where the list of inputs and functions us known at
compile design time.

I suspect cells can be used to implement this, though I haven't used
them. The problem seems very Prolog-y. I wonder if there are any such
frameworks already out there. This would be a great project for
contrib if not.

Thanks,
Johnny

Richard Newman

unread,
Mar 1, 2010, 10:31:58 AM3/1/10
to clo...@googlegroups.com
>> 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

Yaron

unread,
Mar 1, 2010, 8:31:34 PM3/1/10
to Clojure
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.
Reply all
Reply to author
Forward
0 new messages