24

Just started with Scheme. I'm having problem with printing on console. A simple list printing example:

 (define factorial
   (lambda (n)
     (cond 
       ((= 0 n) 1)
       (#t (* n (factorial (- n 1)))))))

I want to print n, every time the function is called. I figured that I can't do that within the same function? Do I need to call another function just so I can print?

dyoo
  • 11,795
  • 1
  • 34
  • 44
eric17859
  • 418
  • 1
  • 5
  • 17

1 Answers1

44

Printing in Scheme works by calling display (and possibly, newline). Since you want to call it sequentially before/after something else (which, in a functional (or in the case of Scheme, functional-ish) language only makes sense for the called functions side-effects), you would normally need to use begin, which evaluates its arguments in turn and then returns the value of the last subexpression. However, lambda implicitly contains such a begin-expression.

So in your case, it would go like this:

 (lambda (n)
   (display n) (newline)
   (cond [...]))

Two remarks:

  1. You can use (define (factorial n) [...]) as a shorthand for (define factorial (lambda (n) [...])).
  2. The way you implement factorial forbids tail call-optimization, therefore the program will use quite a bit of stack space for larger values of n. Rewriting it into a optimizable form using an accumulator is possible, though.

If you only want to print n once, when the user calls the function, you will indeed need to write a wrapper, like this:

 (define (factorial n)
   (display n) (newline)
   (inner-factorial n))

And then rename your function to inner-factorial.

dyoo
  • 11,795
  • 1
  • 34
  • 44
fnl
  • 2,209
  • 19
  • 17
  • You don't need a begin within a lambda body. – Paul Richter Feb 11 '12 at 02:40
  • Oh thx! But how about printing after the condition? I'm not working on factorial actually, but it's easier explaining with it. Something like print only if the condition is true, i.e. print if n!=0. – eric17859 Feb 11 '12 at 02:41
  • 1
    I fixed the part about `begin`. The body of a `cond`-clause may also contain multiple expressions, so you can easily just call `display` there. – fnl Feb 11 '12 at 02:51
  • Sry if I wasn't clear. I mean, if n=5, I would print 1 2 3 4 5 – eric17859 Feb 11 '12 at 02:51
  • I assume you still want to extend `factorial` to do this? Then it would go like: `(define factorial (lambda (n) (cond ((= 0 n) 1) (#t (let ((result (* n (factorial (- n 1))))) (display n) (newline) result)))))` – fnl Feb 11 '12 at 02:59
  • thanks a lot! Can you tell me why you need to create a variable? why it doesn't work with (display n) (newline) (* n (factorial (- n 1))) – eric17859 Feb 11 '12 at 03:17
  • That would also work, but achieve a different effect: Because the current `n` is now printed before the recursive call, the output would be reversed. – fnl Feb 11 '12 at 03:19
  • Hm.. it didn't work. procedure application: expected procedure, given: #; arguments were: # 1.. Ah, I don't get these error msgs. – eric17859 Feb 11 '12 at 03:34
  • Having diverged quite a bit from the original question, I recommend you ask a separate one. – fnl Feb 11 '12 at 03:40
  • 1
    The original answer had a few typos. I've tried to edit the answer to be correct. e.g. `(define factorial (n) ...)` is syntactically incorrect: it should be `(define (factorial n) ...)`. – dyoo Feb 11 '12 at 03:43