0

I want to define a function in scheme that will take a number/letter e.g. x and a list (which can also contain lists) and return the number/letter which comes immediately after x. e.g. (foo 'x '(x (3 x 5 x x 8 9) (10 x 12 13 x 15 yx 17)) => ((3 x 5 x x 8 9) 5 x 8 12 15). I thought I had the code working but then discovered that it will not work if the last element of the list is a list. I would like to change the line ((null? (cdr ls)) '()) to something like ((and((not (list? (ls)))) (null? (cdr ls))) '()) - ie. if the last element is not a list return '() but this does not seem to be valid code. Is there a way that I can have something like this or an if statement without an else?

(define foo
(λ (x ls)
      (cond ((null? ls) ‘())
            ((not (list? ls)) '())
            ((null? (cdr ls)) '())
            ((equal? x (car ls))
               (cons (car(cdr ls))(foo x(cdr ls))))
            ((list? (car ls))
               (append (foo x(car ls))
                       (foo x(cdr ls))))
            (else (foo x (c
Deef
  • 49
  • 2
  • What is the value of "an if statement without an else" when the expression is not true? – Scott Hunter Jan 12 '18 at 15:51
  • Possible duplicate of [My code signals the error "application: not a procedure" or "call to non procedure"](https://stackoverflow.com/questions/48064955/my-code-signals-the-error-application-not-a-procedure-or-call-to-non-procedu) because `ls` and `(not ...)` surely isn't functions. `if` without `else` is giving the implementation the choice of return value when the predicate is false. eg. `(if (null? 'test) 'my-result) ; ==> "Banana!"`. Is that what you are after? – Sylwester Jan 12 '18 at 16:28
  • I can see now why using if on it's own wouldn't work. What I'm trying to do is something like ((null? (cdr ls)) '()) – Deef Jan 12 '18 at 17:39
  • except that where it return '() if ((null? ls) is true it would return '() only if both (not (list? (cdr ls)) and (null ? cdr ls)) are true – Deef Jan 12 '18 at 17:42

1 Answers1

0

The order in which '(null? (cdr ls) '()) is tested is the cause of your problem. Ie. when (car ls) is a list itself, the function still returns '() because '(null? (cdr ls) '()) is evaluated before the case

((list? (car ls))
 (append (foo x (car ls))
         (foo x (cdr ls))))

Consider the following re-order of your cond test cases:

(define (foo x ls)
  (cond
    ((null? ls) '())
    ((not (pair? ls)) '())
    ((pair? (car ls))
     (append (foo x (car ls))
             (foo x (cdr ls))))
    ((null? (cdr ls)) '())
    ((equal? x (car ls))
     (cons (cadr ls) (foo x (cdr ls))))
    (else
     (foo x (cdr ls)))))

Then you would have:

(foo 'x '())
=> '()
(foo 'x '(x))
=> '()
(foo 'x '(x (3 x 5 x x 8 9) (10 x 12 13 x 15 yx 17)))
=> '((3 x 5 x x 8 9) 5 x 8 12 15)
assefamaru
  • 2,751
  • 2
  • 10
  • 14