0

I'm a newbie to scheme programming and I was writing small codes when I encountered the following issue and couldn't reason about it satisfactorily.

(define (at_i lst i)
  (if (eq? i 0)
    (car lst)
    (at_i (cdr lst)
          (- i  1) )))

Evaluation of (at_i '(1 2 3 4) 0) returns 1. Now lets define same procedure with a lambda syntax.

(define (at_i lst i)
  (lambda (vec x)
    (if (eq? x 0)
      (car vec)
      (at_i (cdr vec)
            (- x  1) )))
  lst i)

But now Evaluation of (at_i '(1 2 3 4) 0) returns 0, which is not in the list and in general, it returns element at index-1.

I don't understand why this is happening.

Note: I just realized its not returning element at index - 1 but the index itself. The reason for this has been well explained below by @Renzo. Thanks!

Misgevolution
  • 825
  • 10
  • 22
  • Standard naming convention in Scheme is `at-i`. –  Apr 04 '17 at 12:11
  • Just in case: Scheme's linked list is a fundamentally different data structure than, for example, C++'s dynamic-array based `vec`tor. –  Apr 04 '17 at 12:39

3 Answers3

3

First, you should indent properly the code if you intend to learn the language, since code indentation is very important to understand programs in Scheme and Lisp-like languages.

For instance, your function correctly indented is:

(define (at_i lst i)
  (lambda (vec x)
    (if (eq? x 0)
        (car vec)
        (at_i (cdr vec) (- x  1))))
  lst
  i)

From this you can see that you are defining the function at_i exactly as before in terms of a function with two parameters (lst and i), and whose body is constitued by three expressions: the first lambda (vec x) ... (- x 1)))), which is an (anonymous) function (lambda) which is not called or applied, the second, which is the first parameter lst, and finally the third which is the second parameter i. So, when the function at_i is called with two arguments, the result is the evaluation of the three expressions in sequence, the first two values are discarded (the function and the value of lst), and the result is the value of the second parameter i. This is reason for which the result of (at_i '(1 2 3 4) 0) is 0, since it is the value of i.

A proper redefinition of the function in lambda form would be the following, for instance:

(define at_i
  (lambda (vec x)
    (if (eq? x 0)
        (car vec)
        (at_i (cdr vec) (- x  1)))))

(at_i '(1 2 3 4) 0)  ;; => 1

in which you can see that the name at_i, through the define, is associated to a two parameter function which calculates correctly the result.

Renzo
  • 26,848
  • 5
  • 49
  • 61
1

eq? is memory object equality. Only some Scheme implementations interpret (eq? 5 5) as #t. Use = for numbers, eqv? for values, and equal? for collections.

(define (index i xs)       ; `index` is a partial function,
   (if (= i 0)             ; `i` may go out of range
      (car xs)
      (index (- i 1)       ; Tail recursion
             (cdr xs) )))

Your second function returns the index because you missed parenthesis around the lambda's application. It should be

(define (index i xs)
   ((lambda (i' xs')
       (if (= i' 0)
          (car xs')
          (index (- i' 1)      ; Not tail-recursive
                 (cdr xs') )))
    i xs))

But this is verbose and differs semantically from the first formulation.

-1

You say you are defining the "same procedure with a lambda syntax", but you are not. That would be (define at_i (lambda lst i) ...). Instead, you are effectively saying (define (at_i lst i) 1 2 3), and that is 3, of course.

In your particular case, you defined the procedure at_i to return (lambda (vec x) ...), lst and i. Now, if you call (at_i '(1 2 3 4) 0), the procedure will return 0, since that is the value of i at this point.

Michael Vehrs
  • 3,293
  • 11
  • 10