0
votes

I am trying to print a Pascal's Triangle on terminal using Guile Scheme.
What is Pascal's Triangle?

Here is the script:

 #!/usr/local/bin/guile \
-e main -s 
!#
(define (fact-iter product counter max-count)
    (if (> counter max-count)
         product
         (fact-iter (* counter product) (+ counter 1) max-count)))

(define (factorial n)
    (fact-iter 1 1 n))

(define (n-C-r n r) 
    (/ (factorial n) (* (factorial (- n r)) (factorial r))
    )
)


(define (row-iter r l n)
    (cond   ((= r 0) ((display 1) (row-iter (+ r 1) l n)))
            ((and (> r 0) (< r l)) ((display (n-C-r l r)) (display " ") (row-iter (+ r 1) l n)))
            ((= r l) (display 1))
    )
)


(define (line-iter l n)
    (cond ((<= l n) ( (row-iter 0 l n)
                        (line-iter (+ l 1) n) ) )
    )
)

(define (pascal-triangle n)
    (line-iter 0 n) )

(define (main args)
    (pascal-triangle (string->number (car (cdr args)) 10))
    )

File name is pascalTriangle.scm
The Shebang notation on the top has correct path to guile.
I have given the permissions by chmod +x pascalTriangle.scm
Run the program using the command ./pascalTriangle.scm 5

When run, the above script, the following output/error is observed:

1Backtrace: In ice-9/boot-9.scm:
   157: 5 [catch #t #<catch-closure ac8400> ...]
In unknown file:
     ?: 4 [apply-smob/1 #<catch-closure ac8400>]
In ice-9/boot-9.scm:
     63: 3 [call-with-prompt prompt0 ...]
In ice-9/eval.scm:
   432: 2 [eval # #]
In /home/tarunmaganti/./pascalTriangle.scm:
     27: 1 [line-iter 0 4]
In unknown file:
     ?: 0 [#<unspecified> #<unspecified>]

ERROR: In procedure #<unspecified>:
ERROR: Wrong type to apply: #<unspecified>

Notice that, the first character of the output is 1 which implies that the code executed until first part of procedure row-iter i.e., (display 1) and there might be an error after it.

But the output says that error is in procedure line-iter. I do not understand.
I would appreciate if any error in the program is pointed-out and corrected to make it print a Pascal's Triangle.

Edit1: I edited the error/output text, I replaced '<' and '>' with HTML entities. The text inside the angular brackets wasn't visible before.

2

2 Answers

1
votes

The problem is that you have added excess parentheses around your consequence expressions in cond. Since cond has explicit begin you code that looks like this today:

(define (row-iter r l n)
  (cond ((= r 0)
         ;; you see the double (( ?
         ((display 1)
          (row-iter (+ r 1) l n)))

        ((and (> r 0) (< r l))
         ;; you see the double (( ?
         ((display (n-C-r l r))
          (display " ")
          (row-iter (+ r 1) l n)))

        ((= r l)
         ;; without double (( and thus ok
         (display 1))))

Needs to have it's excess parentheses removed like this:

(define (row-iter r l n)
  (cond ((= r 0)
         (display 1)
         (row-iter (+ r 1) l n))

        ((and (> r 0) (< r l))
         (display (n-C-r l r))
         (display " ")
         (row-iter (+ r 1) l n))

        ((= r l)
         (display 1))))

If you would have used if instead you would have to use begin:

(define (row-iter r l n)
  (if (= r 0)
      (begin
        (display 1)
        (row-iter (+ r 1) l n))
      (if (and (> r 0) (< r l))
          (begin
            (display (n-C-r l r))
            (display " ")
            (row-iter (+ r 1) l n))          
          (display 1))))

Just fixing this procedure wont fix you problem since you have the same error in line-iter as well. You might see double (( in the beginning of each cond term but unless you are doing something fancy you should not expect it anywhere else.

When adding excess parentheses ((display "something") #t) it gets interpreted as (display "something") will return a procedure and that you want to check what the result of that procedure with argument #t will become. When all the parts is evaluated it fails since then it finds out the undefined value is not a procedure. There are cases where it works:

((if (< x 0) - +) x 1) ; absolute increment value without changing sign

Here you see the first part gets evaluated to the result of evaluating - when x is less than zero. If it's -10 the result would be -11 and if it is 10 the procedure applied will be the evaluation of + with the result 11.

Later it will find that the value 3 isn't a procedure and you get th eerror. and to get the result Scheme should do (apply 3 '(#t))and it detects that 3 (in your case whatdesiplayreturns which is an unspecified value) Scheme interprets this by evaluating(display (n-C-r l r)` which prints something and the returned value, which by the spec i undefined and thus free choice of the implementers, is then applied as a procedure because of excess parentheses.

In Guile the result of values undefined in the spec becomes a singleton that displays #<unspecified> and that is ignored by the REPL. You might find a Scheme implementation where the unspecified value is a procedure that takes no arguments where your implementation will work flawlessly but will not be portable.

0
votes

The error as stated by Sylwester in his answer is in ((display (n-C-r l r)) (display " ") (row-iter (+ r 1) l n))) expression. The statement indeed interprets this by evaluating ((display (n-C-r l r)) which prints something and return undefined value and is applied as a procedure considering ((display (n-C-r l r)) as excessively parenthesized.

I resolved the problem using the Sequencing. The begin special form is used to combine multiple statements and returns the value of the last statement. Sequencing in MIT-Scheme. This worked in guile scheme too.

Syntax of begin special form: (begin <e1> <e2> <e3>....<en>)
It returns return value of <en> expression.

Here is the changed code:

(define (row-iter n r) 
    (cond ((= r 0) (begin (display 1) (display " ") (row-iter n (+ r 1))))
          ((and (> r 0) (< r n)) (begin (display (n-C-r n r)) (display " ") (row-iter n (+ r 1))))
          ((= r n) (display 1))
    )
)

Although the output isn't properly formatted as a "triangle", we can get left indented pascal triangle after changing the code.

By running ./pascalTriangle 5, we get the output as

1    
1 1    
1 2 1    
1 3 3 1    
1 4 6 4 1    
1 5 10 10 5 1