1
\$\begingroup\$

I know this is a bit elementary, but I am highly uncomfortable writing Scheme code, and I want to make sure that what I'm doing is good practice. I know mutation is frowned upon in Scheme.

I have no other source of review so I have come to you all.

(define (filter-lst fn lst)
 (if (not (null? lst))
 (if (fn (car lst))
 (cons (car lst) (filter-lst fn (cdr lst)))
 (filter-lst fn (cdr lst))
 )
 '()
 )
)

Note: The function seems to be working according to a few test cases I ran.

As a follow-up PURELY STYLISTIC question, which of these is preferred?

#1

(define (merge l1 l2)
 (if (null? l1) l2
 (if (null? l2) l1
 (cons (car l1) (cons (car l2) (merge (cdr l1) (cdr l2)))))))

#2

(define (merge l1 l2)
 (if (null? l1) l2
 (if (null? l2) l1
 (cons (car l1) (cons (car l2) (interleave (cdr l1) (cdr l2))))
 )
 ) 
)
Toby Speight
87.1k14 gold badges104 silver badges322 bronze badges
asked Apr 12, 2021 at 17:36
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

When you catch yourself using nested ifs, that's usually a sign you'd be better served by the cond form. (which is actually way more powerful than nested if due to a few quirks)

Here's how I'd clean that up

(define (filter-lst fn lst)
 (cond ((null? lst) '())
 ((fn (car lst)) 
 (cons (car lst)
 (filter-lst fn (cdr lst))))
 (else (filter-lst fn (cdr lst)))))

The above isn't entirely idiomatic (which would be to implement it as a one-liner fold with a lambda.) but does show off a few style notes. Of your choices I'd say #1 is closest to the preferred style.

First is where you may be tempted to tab, a double space will do as I do on the second line, its usually appropriate to distinct parts separate certain special forms particularly (define, let, cond). You really want to avoid creeping to the right any faster than necessarily.

(define (merge l1 l2)
 (if (null? l1) l2
 (if (null? l2) l1 (cons (car l1) (cons (car l2) (merge (cdr l1) (cdr l2)))))))

Second is that if you split a function, there should be one argument per line, aligned to the start of the first argument

(define (merge l1 l2)
 (if (null? l1) 
 l2
 (if (null? l2) 
 l1 
 (cons (car l1) 
 (cons (car l2) 
 (merge (cdr l1) (cdr l2)))))))

And you see why cond is preffered again

(define (merge l1 l2)
 (cond ((null? l1) l2)
 ((null? l2) l1)
 (else (cons (car l1) 
 (cons (car l2) 
 (merge (cdr l1) (cdr l2))))))

And if a spot seems unwieldy there are often algorithmic simplifications that are worth considering

(define (merge l1 l2)
 (if (null? L1) 
 l2
 (cons (car l1)
 (merge l2 l1))))
answered Apr 28, 2021 at 7:07
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.