0
(defun foo (in i out)
    (if (>= i 0)
        (progn
            (append (list (intern (string (elt in i)))) out)
            (print output)
            (foo in (- i 1) out )
        )       
        (out)
    )
)

(print (foo "abcd" (- (length "abcd") 1) (list)))

I am trying to return this string as (a b c d). But it does return nil as output. What do I do wrong here? Thanks

2
  • 2
    There are a lot of basics wrong. Maybe you should read and work through an introductory book: cs.cmu.edu/~dst/LispBook You can download the book for free as a PDF from there. Commented Oct 20, 2019 at 12:28
  • 3
    Have you actually tried to run the code? It doesn't do what you claim. Commented Oct 20, 2019 at 12:29

2 Answers 2

2

I don’t know what this has to do with appending. I think your desired output is also weird and you shouldn’t do what you’re doing. The right object for a character is a character not a symbol. Nevertheless, a good way to get the list (a b c d) is as follows:

CL-USER> '(a b c d)

Interning symbols at runtime is weird so maybe you would like this:

(defconstant +alphabet+ #(a b c d e f g h i j k l m n o p q r s t u v w x y z))

(defun foo (seq)
  (map 'list
       (lambda (char)
          (let ((index (- (char-code char) (char-code #\a))))
            (if (< -1 index (length +alphabet+))
                (svref +alphabet+ index)
                (error "not in alphabet: ~c" char))))
       seq))
Sign up to request clarification or add additional context in comments.

Comments

1

You have just some minor mistakes. First, we need to get rid of output and (output); these bear no relation to the code. It seems you were working with a variable called output and then renamed it to out without fixing all the code. Moreover, (output) is a function call; it expects a function called output to exist.

Secondly, the result of append must be captured somehow; in the progn you're just discarding it. Here is a working version:

(defun foo (in i out)
  (if (>= i 0)
    (foo in (1- i) (cons (intern (string (elt in i))) out))
    out))

Note also that instead of your (append (list X) Y), I'm using the more efficient and idiomatic (cons X Y). The result of this cons operation has to be passed to foo. The out argument is our accumulator that is threaded through the tail recursion; it holds how much of the list we have so far.

I.e. we can't have (progn <make-new-list> (foo ... <old-list>)); that just creates the new list and throws it away, and then just passes the old list to the recursive call. Since the old list initially comes as nil, we just keep passing along this nil and when the index hits zero, that's what pops out. We need (foo .... <make-new-list>), which is what I've done.

Tests:

[1]> (foo "" -1 nil)
NIL
[2]> (foo "a" 0 nil)
(|a|)
[3]> (foo "ab" 1 nil)
(|a| |b|)
[4]> (foo "abcd" 3 nil)
(|a| |b| |c| |d|)
[5]> (foo "abcd" 3 '(x y z))
(|a| |b| |c| |d| X Y Z)

Lastly, if you want the (|a| |b| |c| |d|) symbols to appear as (a b c d), you have to fiddle withreadtable-case.

Of course:

[6]> (foo "ABCD" 3 nil)
(A B C D)

Comments

Your Answer

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.