   DrScheme help
  Ok I am trying to teach myself scheme because I am taking an introductory course to AI and I know relatively little about scheme.  I am currently reading The Scheme Programming Language 2nd edition by R. Kent DyBvig, anyhow it has a simple scheme problem that for some reason I am not getting and I know its very easy.;; Exercise 2.8.3 ;; make-list;; takes a nonnegative integer n and an object;; returns new list, n long, each element of which is the object(define make-list  (lambda (n o)    (cond ((= n 0) list o) ((list o o) make-list (- n 1) o))))I thought that scheme just created the list o o 7 times and would then give me ((), (), (), (), (), (), ()) but it always just gives me this> (make-list 7 '())()Its been a long time since I used scheme and I am trying to refresh my memory about how it works.   
  When you call a function you must always surround the call with parentheses. For example, you call a function f with the arguments x and y like this:(f x y)You forgot to do this when calling the functions in the body of the conditions.Also, when you post code, surround it with [code] and  tags or [source] and [/source] tags, if it's a long block   ;  Thanks for the fellow Kansas Citizen!   ;  0) As noted: you need to surround function calls with parentheses. Otherwise, the function is treated as just an ordinary object (a "thing" that might be part of a list), and not actually called. The list ((= n 0) list o) is the list (<boolean value indicating if n is equal to zero>, <the function 'list'>, <the object 'o'>). Whereas the list ((= n 0) (list o)) is the list (<boolean value indicating if n is equal to zero>, <list consisting of one instance of the object 'o'>).1) When you call (cond), every argument supplied needs to be a pair of (condition, corresponding value). Right now, your second argument has a "condition" of (list o o), which is not what you want. To make the 'default' case, use a condition that is always true; the normal way to do that is to use the boolean "true" value, which in Scheme is spelled '#t'.2) It looks like what you were hoping to do was append the list (list o o) to the list (make-list (- n 1) o) in the default case. Just putting two lists together like that isn't going to do the trick. Not even if you put an extra set of parentheses and add the appropriate condition - because the list ((a b) (c d)) is not the same as the list (a b c d).You don't actually want to put the "extra" o into its own list at all, actually. What you're trying to do is append an element o to the list returned from (make-list (- n 1) o). In Scheme, we do that with (cons).3) When n is zero, you want to return a list that is zero elements long. (list o) is a list that is one element long, because it contains an 'o'. To make an empty list, use (), or nil.   ;  Thanks to Zahlman you know where you're going wrong. He speaks wisdom about understanding lists: (cons a b) prepends the element a to the list b, or if b is not a list, makes the pair (a . b). The important thing to realize is that they do the same thing: a list is simply a pair where the second element is a list!Experiment in DrScheme, see what you get if you do these, and understand why. The second and fourth examples are proper lists, the first and third are not. Scheme is an extremely simple language, but you do need to understand linked lists to use it effectively:> (cons 1 2)(1 . 2)> (cons 1 (list 2))(1 2)> (cons (list 1) 2)((1) . 2)> (cons (list 1) (list 2))((1) 2)Given that you know what you're doing wrong, here's how to do it right:First, the lambda version. In this case, you're binding the name make-list to an anonymous function (the lambda) that does the actual work. Understand the difference between binding and assignment, google it if you don't.Notice the function calls itself recursively: thank your lucky stars that the (define ...) special form lets the name it binds be visible within it, otherwise you'd have to use the Y combinator to write this. The Y combinator is known for making brains explode.(define make-list  (lambda (n obj)    (cond  ((= n 0)  (list)) (#t  (cons obj (make-list (- n 1) obj))))))That's perfectly fine scheme code, but there's an alternative: you can use define to define functions directly, without having to bind their name to an anonymous function as before. Shorthand notation. This is a question of style ((define ...) lets the name it's binding be visible within it, so you can define recursive functions with the syntax above). I find it more readable, but other people might have different preferences: (define (make-list2 n obj)  (cond    ((= n 0)(list))    (#t(cons obj (make-list (- n 1) obj)))))Now, syntax aside, this code is equivalent to the above. It's fine, but it runs in linear space because part of the state is kept in the call stack. If we're optimizing for efficiency (algorithmic efficiency, not low level hacks) we'll notice that this function doesn't require linear space. We notice it can be expressed tail recursively (google for tail recursion if you're not familiar with the term). The scheme standard requires scheme compilers to perform tail call elimination, so if we express the algorithm tail-recursively we can be certain it'll run in constant space.We can define a function in the scope of a (define ...) that is visible inside it.This is a common idiom in functional languages: we define a helper function that passes state explicitly (res, the result state when the recursion reaches its termination condition) as an argument instead of keeping it implicit in the call stack as in the previous version, to let the compiler turn it into a constant-space iteration:(define (make-list3 n obj)  (define (make-list-helper res n obj)    (cond ((= n 0) res)(#t (make-list-helper (cons obj res) (- n 1) obj))))  (make-list-helper (list) n obj))And we're done. make-list3 runs in constant space and is what a competent scheme programmer would write given the exercise above.Actually, it's not, but almost: obj doesn't change within the scope of the outermost define, so we don't have to pass it around in the helper function:(define (make-list4 n obj)  (define (make-list-helper res n)    (cond ((= n 0) res)(#t (make-list-helper (cons obj res) (- n 1)))))  (make-list-helper (list) n))