Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
454 views
in Technique[技术] by (71.8m points)

lisp - Trying to compute gross pay

I'm trying to create a program that will compute for weekly the gross-pay of an employee.

and here's my code

(princ"Enter working hours: ")
(defparameter workhours(read))
(if (and (>= workhours 0)) (<= workhours 60))
    (princ"Enter hourly pay rate: ")
    (defparameter HPrate(read))
    (if(<= workhours 40)
        (* workhours HPrate))

I'm having difficulty in constructing this 40*HPrate + (workhours - 40) * HPrate * 1.5 in lisp

Here's the formula

(Regular hours/week) Gross Pay = Hours X Rate
(With Overtime) Over Time Pay = ( Hours - 40 ) X Rate X 1.5
Gross Pay = 40 X Rate + Over Time Pay
question from:https://stackoverflow.com/questions/66064278/trying-to-compute-gross-pay

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You should try to separate the logic of your code from input/output operations, like asking for numbers or writing results. It is often best to just write functions that are given numbers and output numbers. Then, you can call it from any kind of user-interface, graphical or textual.

Business logic

You want to compute the gross pay given a number of work hours and an hourly rate.

So you define a function, named gross-pay, which takes as input a number of work-hours, and a hourly-rate:

(defun gross-pay (work-hours hourly-rate)
  10000 ;; a lot of money, just for testing
  )

Now that it is defined, you can call it, and your environment will print the result automatically:

* (gross-pay 0 0)
10000 

One of the problems in your code is that you have an if branch with one test and three branches, which is not a valid syntax. Based on what you wrote, I guess you wanted to have this logic:

(defun gross-pay (work-hours hourly-rate)
  (assert (<= 0 work-hours 60))
  ;; ...
  )

The assert checks if the condition holds, and signals an error otherwise. I think there is no valid computation in case the number of hours is below zero or greater than 60, in which case it makes sense to have an error.

Then, you want to compute the gross-pay, with the formula you gave.

You have to compute the number of regular hours, the number of over-time, and price both kinds of hours differently (and sum them).

Let's define an auxiliary function, split-time, which returns two values, the amount of hours below or equal to 40, and the remaining time (over 40):

(defun split-time (hours)
  (if (> hours 40)
      ;; the regular amount is maxed to 40
      ;; overtime is the rest
      (values 40 (- hours 40))
      ;; regular amount is the same as the input
      ;; no overtime
      (values hours 0)))

You can get the result of multiple values by using multiple-value-bind, as follows:

(defun gross-pay (work-hours hourly-rate)
  (assert (<= 0 work-hours 60))
  (multiple-value-bind (regular overtime) (split-time work-hours)
    ;; here regular and overtime are bound to values
    ))

Finally:

(defun gross-pay (work-hours hourly-rate)
  (assert (<= 0 work-hours 60))
  (multiple-value-bind (regular overtime) (split-time work-hours)
    (+ (* regular  hourly-rate)
       (* overtime hourly-rate 3/2))))

Here, I am using 3/2 instead of 1.5 because floating-point computation is approximate, but rational numbers are precise. The result can be converted back to a float when printing it, for example.

Tests

Now that you have a function, you can test it:

* (gross-pay 10 1)
10

* (= (gross-pay 50 1)
     (+ (* 40 1) 
        (* 10 3/2)))
T

Input/output

You can wrap the logic in command-line interface if you want:

(defun gross-pay/io ()
  (gross-pay
   (ask "Enter working hours: " '(integer 0 60))
   (ask "Enter hourly pay rate: " '(integer 1 1000))))

The above works thanks to this helper function, which takes care of different issues that may arise when asking for inputs (clearing buffering, forcing output, disabling evaluation when reading values, checking for a type, etc.)

(defun ask (prompt type)
  (let ((*standard-output* *query-io*))
    (loop
      (clear-input)
      (fresh-line)
      (princ prompt)
      (finish-output)
      (let ((value (let ((*read-eval* nil)) (read))))
        (if (typep value type)
            (return value)
            (format *error-output*
                    "type mismatch: ~a not of type ~a"
                    value type))))))

In my environment, here is an example interaction:

USER> (gross-pay/io)

Enter working hours: 5

Enter hourly pay rate: 3

15

And an example of bad input:

Enter working hours: 87
type mismatch: 87 not of type (INTEGER 0 60)
Enter working hours: ""
type mismatch:  not of type (INTEGER 0 60)
Enter working hours: 15

Enter hourly pay rate: 0
type mismatch: 0 not of type (INTEGER 1 1000)
Enter hourly pay rate: 88

1320

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...