4
votes

My name is Michael Boutros and I'm currently a senior in high school. Next year I'll be attending the University of Waterloo and as a primer to their CS courses, I've been going through and doing some of the assignments. The language they use is Scheme and I've been learning it as I go along. I come from a PHP and Ruby background, so I'm worried that some of my habits learned from those languages are being applied incorrectly to what I'm doing with scheme. Here's the question from the assignment (available online, by the way):

Write a function called sub-time that consumes a string start-time representing a time, and a natural number mins which represents the number of minutes before. The function produces a string representing mins minutes before the given time start-time.

The string consumed will be formatted as follows: a two digit number, followed by “ hours ”, followed by a two digit number, followed by “ minutes”. The time consumed is in 24-hour format. If the number of hours or minutes is less than 10, then the number will include a leading 0. The string produced must be in exactly the following format: a number, followed by “ hours ”, followed by a number, followed by “ minutes”. Note that the string produced does not have a leading 0 before numbers less than 10. It is possible that the time produced could represent a time on a previous day.

For example,
• (sub-time “03 hours 15 minutes” 0) produces
“3 hours 15 minutes”,
• (sub-time “13 hours 05 minutes” 845) produces
“23 hours 0 minutes”, and
• (sub-time “13 hours 05 minutes” 2881) produced
“13 hours 4 minutes”

The built-in Scheme functions string->number and number->string may be useful.

It is very important that you produce the string exactly as described, otherwise the autotests will fail. In particular, all characters must be in lower case and there must be single spaces between all parts of the string.

Do not use any cond expressions in your solution.

(Honestly, I didn't even notice the last line until just now, and my solution does use conditional expressions. Is there any way to avoid them?)

Here is my solution:

;; Assignment 1 Question 4
(define (convert-to-string hours minutes)
  (string-append (number->string hours) " hours " (number->string minutes) " minutes"))

(define (subtract_hours start_hours sub_hours minutes)
  (let ((hours (- start_hours (modulo sub_hours 24))))
    (if (< hours 0)
        (convert-to-string (+ 24 hours) minutes)
        (convert-to-string hours minutes))))

(define (subtract_minutes start_hours start_minutes sub_hours sub_minutes)
  (let ((minutes (- start_minutes sub_minutes)))
    (if (< minutes 0)
        (subtract_hours start_hours (+ 1 sub_hours) (+ 60 minutes))
        (subtract_hours start_hours sub_hours minutes))))

(define (sub-time start-time mins)
  (let ((start_hours (string->number (substring start-time 0 2))) 
        (start_minutes (string->number (substring start-time 9 11)))
        (sub_hours (quotient mins 60))
        (sub_minutes (modulo mins 60)))        
    (subtract_minutes start_hours start_minutes sub_hours sub_minutes)))

I'm incredibly new to Scheme and although my solution works (from my limited testing), I'm wondering what some seasoned veterans have to say. Thanks for your time!

2
I think, the cond here refers to the cond macro, not conditional expressions in general...Dirk
Kudos for doing the assignments for fun!JasonFruit

2 Answers

2
votes

Yes, you can write this code without any conditionals. Think about converting the hours+minutes to the number of minutes, then doing the subtraction, then converting the result back to hours+minutes.

0
votes

I had a go at doing the answer using the minute conversion idea and come up with something that seems to work. It seems up for debate whether we are allowed to used conditionals or not, so I played it safe and did not use any.

Unfortunately, I don't know anything about Scheme but hopefully this code is vanilla enough that you should be able to convert.

int offset; //the mins we are going to subtract
int startTimeInMins = inputHours * 60;
startTimeInMins += inputMins;

int offsetDayRolled = offset mod 1440;
int newTime = startTimeInMins - offsetDayRolled;

newTime += 1440;
newTime = newTime mod 1440;

int newHours = newTime / 60;
int newMins = newTime mod 60;