From: ·········@yahoo.com
Subject: Searching with find
Date: 
Message-ID: <1129764980.732310.173840@g43g2000cwa.googlegroups.com>
I am trying to write a function citx2 that returns a list based upon
status and income.
For example  (citx2 single 150000) should return (single 146750 319100
0.33 12710.50)

The code below does not appear to work.

(defun citx2 (status income)
  (let ((lst (list status income))
    (find lst itx2 :test test-itx2))))

(defun test-itx2 (lst el)
  (and (eql (car lst) (car el))
          (<= (second el) (second lst))
          (<    (second lst) (third el))))

(defparameter itx2 '(
(single 100000 146750 0.28 5373.00)
(single 146750 319100 0.33 12710.50)
(single 319100 10000000 0.35 19092.50)
(married-filing-jointly 100000 117250 0.25 6525.00)
(married-filing-jointly 117250 178650 0.28 10042.50)
(married-filing-jointly 178650 319100 0.33 18975.00)
(married-filing-jointly 319100 10000000 0.35 25357.00)
(married-filing-separately 100000 159550 0.33 9487.50)
(married-filing-separately 159550 10000000 0.35 12678.50)
(head-of-household 100000 100500 0.25 4400.00)
(head-of-household 100500 162700 0.28 7415.00)
(head-of-household 162700 319000 0.33 15500.00)
(head-of-household 319000 10000000 0.35 21932.00)))

From: ·········@yahoo.com
Subject: Re: Searching with find
Date: 
Message-ID: <1129765288.800232.201340@g43g2000cwa.googlegroups.com>
This is a prolog version of the code that works correctly:

rc2(Status,Income,Rate):-
  itx2(Status,Min,Max,MA,SA), Income >= Min, Income < Max, Rate is
(Income * MA) - SA.
tx2(single,100000,146750,0.28,5373.00).
itx2(single,146750,319100,0.33,12710.50).
itx2(single,319100,10000000,0.35,19092.50).

itx2(married_filing_jointly,100000,117250,0.25,6525.00).
itx2(married_filing_jointly,117250,178650,0.28,10042.50).
itx2(married_filing_jointly,178650,319100,0.33,18975.00).
itx2(married_filing_jointly,319100,10000000,0.35,25357.00).

itx2(married_filing_separately,100000,159550,0.33,9487.50).
itx2(married_filing_separately,159550,10000000,0.35,12678.50).

itx2(head_of_household,100000,100500,0.25,4400.00).
itx2(head_of_household,100500,162700,0.28,7415.00).
itx2(head_of_household,162700,319000,0.33,15500.00).
itx2(head_of_household,319000,10000000,0.35,21932.00).
~
From: Kalle Olavi Niemitalo
Subject: Re: Searching with find
Date: 
Message-ID: <87oe5kljbk.fsf@Astalo.kon.iki.fi>
·········@yahoo.com writes:

> For example  (citx2 single 150000) should return (single 146750 319100
> 0.33 12710.50)

You need to call it like (citx2 'single 150000).

> (defun citx2 (status income)
>   (let ((lst (list status income))
>     (find lst itx2 :test test-itx2))))

One closing parenthesis is in the wrong line.

Write test-itx2 as either 'test-itx2 as #'test-itx2 so that it
won't be taken as the name of a variable.  (If test-itx2 were
a local function, you'd have to use #'test-itx2, but as it is
global, 'test-itx2 will work too.)
From: Nelson Marcelino
Subject: Re: Searching with find
Date: 
Message-ID: <1129807501.450185.223810@g47g2000cwa.googlegroups.com>
(defun citx2 (status income)
  (let ((lst (list status income)))
    (find lst itx2 :test #'test-itx2)))

(defun test-itx2 (lst el)
  (and (eql (car lst) (car el))
          (<= (second el) (second lst))
          (<    (second lst) (third el))))

(defparameter itx2 '(
(single 100000 146750 0.28 5373.00)
(single 146750 319100 0.33 12710.50)
(single 319100 10000000 0.35 19092.50)
(married-filing-jointly 100000 117250 0.25 6525.00)
(married-filing-jointly 117250 178650 0.28 10042.50)
(married-filing-jointly 178650 319100 0.33 18975.00)
(married-filing-jointly 319100 10000000 0.35 25357.00)
(married-filing-separately 100000 159550 0.33 9487.50)
(married-filing-separately 159550 10000000 0.35 12678.50)
(head-of-household 100000 100500 0.25 4400.00)
(head-of-household 100500 162700 0.28 7415.00)
(head-of-household 162700 319000 0.33 15500.00)
(head-of-household 319000 10000000 0.35 21932.00)))

CL-USER 1> (citx2 'single 150000)
(SINGLE 146750 319100 0.33 12710.5)

CL-USER 2> (citx2 'married-filing-jointly 150000)
(MARRIED-FILING-JOINTLY 117250 178650 0.28 10042.5)

now works correctly. Just curious, is there any other idiomatic (better
or more concise) way of doing this?
From: Pascal Bourguignon
Subject: Re: Searching with find
Date: 
Message-ID: <87mzl43ult.fsf@thalassa.informatimago.com>
"Nelson Marcelino" <·········@gmail.com> writes:

> (defun citx2 (status income)
>   (let ((lst (list status income)))
>     (find lst itx2 :test #'test-itx2)))
>
> (defun test-itx2 (lst el)
>   (and (eql (car lst) (car el))
>           (<= (second el) (second lst))
>           (<    (second lst) (third el))))
>
> (defparameter itx2 '(...))
>
> CL-USER 1> (citx2 'single 150000)
> (SINGLE 146750 319100 0.33 12710.5)
>
> CL-USER 2> (citx2 'married-filing-jointly 150000)
> (MARRIED-FILING-JOINTLY 117250 178650 0.28 10042.5)
>
> now works correctly. Just curious, is there any other idiomatic (better
> or more concise) way of doing this?

Yes. The idiomatic name for generic list in lisp is list.

 (defun citx2 (status income)
   (let ((list (list status income)))
     (find list itx2 :test #'test-itx2)))

 (defun test-itx2 (list el)
   (and (eql (car list) (car el))
        (<= (second el)   (second list))
        (<  (second list) (third el))))


When you use a variable only once, it may be good to avoid the binding:

(defun citx2 (status income) 
    (find  (list status income) itx2 :test #'test-itx2))


The idiomatic convention for special (global) variables is to enclose
them in stars:

(defparameter *itx2* '( ...))

(defun citx2 (status income) 
    (find  (list status income) *itx2* :test #'test-itx2))

What more concise than a one-liner do you want?  Try APL!





-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
You never feed me.
Perhaps I'll sleep on your face.
That will sure show you.
From: Thomas A. Russ
Subject: Re: Searching with find
Date: 
Message-ID: <ymi3bmw2gmo.fsf@sevak.isi.edu>
·········@yahoo.com writes:


> I am trying to write a function citx2 that returns a list based upon
> status and income.
> For example  (citx2 single 150000) should return (single 146750 319100
> 0.33 12710.50)
> 
> The code below does not appear to work.

It would have helped if you told us how it was failing.  ;)


> (defun citx2 (status income)
>   (let ((lst (list status income))
>     (find lst itx2 :test test-itx2))))

Kalle pointed out the bug in this function.

> (defun test-itx2 (lst el)
>   (and (eql (car lst) (car el))
>           (<= (second el) (second lst))
>           (<    (second lst) (third el))))

Hmmm.  A tax application.

One thing that would help would be to introduce a bit more structure or
organization to your data.  You can do this in a number of ways.  One
would be to use DEFSTRUCT to build your data structures.  That would
involve a little bit more work up-front.

Another would  be to keep the list structure as your basic data
structure , but to define accessor macros.  For example:

(defmacro filing-status (list) `(first ,list))
(defmacro income (list) `(second ,list))

(defmacro income-lower-bound (list) `(second ,list))
(defmacro income-upper-bound (list) `(third ,list))

This allows you to do things like write your test function in a more
self-documenting way:

(defun matching-tax-data (candidate table-entry)
   (and (eql (filing-status candidate) (filing-status table-entry))
        (<=  (income-lower-bound table-entry) (income candidate))
        (<   (income candidate) (income-upper-bound table-entry))))

> (defparameter itx2 '(
> (single 100000 146750 0.28 5373.00)
> (single 146750 319100 0.33 12710.50)
> (single 319100 10000000 0.35 19092.50)
> (married-filing-jointly 100000 117250 0.25 6525.00)
> (married-filing-jointly 117250 178650 0.28 10042.50)
> (married-filing-jointly 178650 319100 0.33 18975.00)
> (married-filing-jointly 319100 10000000 0.35 25357.00)
> (married-filing-separately 100000 159550 0.33 9487.50)
> (married-filing-separately 159550 10000000 0.35 12678.50)
> (head-of-household 100000 100500 0.25 4400.00)
> (head-of-household 100500 162700 0.28 7415.00)
> (head-of-household 162700 319000 0.33 15500.00)
> (head-of-household 319000 10000000 0.35 21932.00)))

Another way of organizing this would involve using a two-level data
structure.  You could do this with association lists (alists).  Note
that by convention, Lisp programmers delimit global variables with "*"
characters.

(defparameter *tax-tables*
    '((single
       (100000 146750 0.28 5373.00)
       (146750 319100 0.33 12710.50)
       (319100 10000000 0.35 19092.50))
      (married-filing-jointly
       (100000 117250 0.25 6525.00)
       (117250 178650 0.28 10042.50)
       (178650 319100 0.33 18975.00)
       (319100 10000000 0.35 25357.00))
      (married-filing-separately 
       (100000 159550 0.33 9487.50)
       (159550 10000000 0.35 12678.50))
      (head-of-household
       (100000 100500 0.25 4400.00)
       (100500 162700 0.28 7415.00)
       (162700 319000 0.33 15500.00)
       (319000 10000000 0.35 21932.00))))

Then you can rewrite your search functions like:

(defmacro income-lower-bound (table-line)
  `(first ,table-line))
(defmacro income-upper-bound (table-line)
  `(second ,table-line))
(defmacro marginal-tax-rate (table-line)
  `(third ,table-line))
(defmacro base-tax (table-line)
  `(fourth ,table-line))

(defun citx2 (status income)
  (find income (rest (assoc status *tax-tables*))
	:test #'income-in-range))

(defun income-in-range (income table-line)
  (<= (income-lower-bound table-line) income)
  (<  income (income-upper-bound table-line)))

NB.  You might want to include the lower levels of the table as well :)

Then you could easily write

(defun compute-tax (status income)
  (let ((table-line (citx2 status income)))
    (+ (base-tax table-line)
       (* (marginal-tax-rate table-line)
           (- income (income-lower-bound table-line))))))

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Bulent Murtezaoglu
Subject: Re: Searching with find
Date: 
Message-ID: <87y84nq4g1.fsf@p4.internal>
>>>>> "TAR" == Thomas A Russ <···@sevak.isi.edu> writes:
[...]
    TAR> One thing that would help would be to introduce a bit more
    TAR> structure or organization to your data.  You can do this in a
    TAR> number of ways.  One would be to use DEFSTRUCT to build your
    TAR> data structures.  That would involve a little bit more work
    TAR> up-front.

Yes.  But 

    TAR> Another would be to keep the list structure as your basic
    TAR> data structure , but to define accessor macros.  For example:

    TAR> (defmacro filing-status (list) `(first ,list)) (defmacro
    TAR> income (list) `(second ,list))

    TAR> (defmacro income-lower-bound (list) `(second ,list))
    TAR> (defmacro income-upper-bound (list) `(third ,list))  [...]

A similar thing can be accomplished by defstruct:

CL-USER> (defstruct (tax-datum (:type list) (:conc-name nil)) 
  filing-status income-lower-bound income-upper-bound 
  other-entry)
TAX-DATUM
CL-USER> (filing-status 
        '(married-filing-separately 159550 10000000 0.35 12678.50))
MARRIED-FILING-SEPARATELY
CL-USER> (income-lower-bound 
         '(married-filing-separately 159550 10000000 0.35 12678.50))
159550

cheers,

BM