Search code examples
schemelisp

Converting a python method into a scheme procedure


I am learning scheme a bit and writing methods basically by first, writing that method in python (recursively) and then translating it into scheme. For example, here is an attempt at writing an list index position:

def idx(elem, l, n=0):
    "Recursive routine for [1,2,3].index(2)"
    if not l:
        return -1
    else:
        return n if (l[0] == elem) else idx(elem, l[1:], n+1)

idx(2, [1,2,3])
# 1

Translating it:

(define (get-idx elem List n)
  (if (= (length List) 0) -1 
  (if 
    (equal? (car List) elem) 
    n
    (get-idx elem (cdr List) (+ n 1)))))

A few questions on this:

  • How could I remove the need to pass the n (current index increment) to the function? Would I need to have a wrapper function around it or what's the usual way to do that?
  • Other than that, how can it be formatted/made cleaner?

I suppose one way to make it 'cleaner' might be to have it as:

(define (get-idx-internal elem List n)
  (if (= (length List) 0) -1 
    (if (equal? (car List) elem) n
      (get-idx-internal elem (cdr List) (+ n 1)))))

(define (get-idx elem List) (get-idx-internal elem List 0))
(display (get-idx 3 (list 1 2 3 4 5)))

; 2

Solution

  • Addressing your first question: your approach is fine, in Scheme we pass the values that get modified as parameters during the recursive call. And some dialects (like Racket) support optional arguments, so we can declare the procedure just like you did in Python:

    ; now it's not necessary to pass `n` when calling it
    (define (get-idx elem lst [n 0])
    

    To make it a bit more idiomatic, we could rewrite your solution like this:

    (define (get-idx elem lst [n 0])
      (cond ((null? lst) -1)
            ((equal? (car lst) elem) n)
            (else (get-idx elem (cdr lst) (add1 n)))))
    
    • It's simpler to use cond, instead of nesting if expressions.
    • Using length for checking if the list is empty is a big no-no (it'll traverse the whole list, making your algorithm quadratic!), use null? instead.
    • Don't call a parameter list, there's a built-in procedure with that name.
    • Prefer add1 for adding 1 to a number, if your Scheme dialect supports it.

    Last but not least, check if your interpreter already provides a procedure for what you want to do; for example: in Racket we have index-of which does the same thing.