HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Project Euler 1 (sum of multiples of 3 or 5 under 1000)

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
underprojectmultipleseuler1000sum

Problem

I solved this a while ago. In the moment I solved it I was learning Scheme and, well, I still am. I'm not looking at the best solution (I searched for it and coded it already, in Python), what I want is to improve this code, maintaining the same (brute) approach, so I can learn some best practices and tips in Scheme. Maybe there are some suggestions on how I wrote the routines, for example.

#lang racket
(define (check x) (or (= (modulo x 3) 0)
                      (= (modulo x 5) 0)))

(define (count-check x) (if (check x)
                            x
                            0))

(define (sum-multiples-rec actual limit acc) (if (< actual limit)
                                                 (sum-multiples-rec (+ actual 1) limit (+ (count-check actual) acc))
                                                 acc))

(define (sum-multiples lower-limit upper-limit) (sum-multiples-rec lower-limit upper-limit 0))

(sum-multiples 0 1000)

Solution

So, any time you want to write a "helper" recursive function, the standard way to write that is to use a named let. So here's how I might restructure your program (but keeping the same algorithm):

(define (sum-multiples start end)
  (let loop ((sum 0)
             (i start))
    (cond ((>= i end) sum)
          ((or (zero? (modulo i 3))
               (zero? (modulo i 5)))
           (loop (+ sum i) (add1 i)))
          (else (loop sum (add1 i))))))


Named let is a macro, which in this case expands to the same expression as:

(define (sum-multiples start end)
  ((letrec ((loop (lambda (sum i)
              (cond ((>= i end) sum)
                    ((or (zero? (modulo i 3))
                         (zero? (modulo i 5)))
                     (loop (+ sum i) (add1 i)))
                    (else (loop sum (add1 i)))))))
     loop)
   0 start))


(I've taken the liberty of using (add1 i) instead of (+ i 1) since you're using Racket.)

Here's a version that's even more Rackety, using for/sum to accumulate the sum rather than using a manual loop:

(define (sum-multiples start end)
  (for/sum ((i (range start end)))
    (if (or (zero? (modulo i 3))
            (zero? (modulo i 5)))
        i 0)))

Code Snippets

(define (sum-multiples start end)
  (let loop ((sum 0)
             (i start))
    (cond ((>= i end) sum)
          ((or (zero? (modulo i 3))
               (zero? (modulo i 5)))
           (loop (+ sum i) (add1 i)))
          (else (loop sum (add1 i))))))
(define (sum-multiples start end)
  ((letrec ((loop (lambda (sum i)
              (cond ((>= i end) sum)
                    ((or (zero? (modulo i 3))
                         (zero? (modulo i 5)))
                     (loop (+ sum i) (add1 i)))
                    (else (loop sum (add1 i)))))))
     loop)
   0 start))
(define (sum-multiples start end)
  (for/sum ((i (range start end)))
    (if (or (zero? (modulo i 3))
            (zero? (modulo i 5)))
        i 0)))

Context

StackExchange Code Review Q#46379, answer score: 6

Revisions (0)

No revisions yet.