Невозможно понять ошибку в коде схемы хитрости

Я пытаюсь распечатать треугольник Паскаля на терминале, используя схему хитрости.
Что такое треугольник Паскаля?< /а>

Вот сценарий:

 #!/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))
    )

Имя файла — pascalTriangle.scm
Обозначение Shebang вверху имеет правильный путь к guile.
Я дал разрешения chmod +x pascalTriangle.scm
Запустите программу с помощью команды ./pascalTriangle.scm 5

При запуске вышеуказанного скрипта наблюдается следующий вывод/ошибка:

1Backtrace: В ice-9/boot-9.scm:
157: 5 [catch #t #‹catch-close ac8400› ...]
В неизвестном файле:
?: 4 [apply- smob/1 #‹catch-close ac8400›]
В ice-9/boot-9.scm:
63: 3 [call-with-prompt prompt0 ...]
В ice-9/ eval.scm:
432: 2 [eval # #]
В /home/tarunmaganti/./pascalTriangle.scm:
27: 1 [line-iter 0 4]
В неизвестном файле:
?: 0 [#‹не указано› #‹не указано›]

ОШИБКА: В процедуре #‹unspecified›:
ОШИБКА: Неправильный тип для применения: #‹unspecified›

Обратите внимание, что первый символ вывода равен 1, что означает, что код выполнялся до первой части процедуры row-iter, т. е. (отображение 1), и после этого может быть ошибка.

Но вывод говорит, что ошибка в процедуре line-iter. Я не понимаю.
Буду признателен, если любая ошибка в программе будет указана и исправлена, чтобы заставить ее печатать треугольник Паскаля.

Edit1: я отредактировал текст ошибки/вывода, заменил «‹» и «›» на объекты HTML. Текст внутри угловых скобок раньше не был виден.


person Tarun Maganti    schedule 24.06.2016    source источник


Ответы (2)


Проблема в том, что вы добавили лишние круглые скобки вокруг выражений последствий в cond. Поскольку cond имеет явный begin код, который сегодня выглядит так:

(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))))

Необходимо удалить лишние скобки следующим образом:

(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, вам пришлось бы использовать 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))))

Простое исправление этой процедуры не решит вашу проблему, так как у вас такая же ошибка и в line-iter. Вы можете увидеть двойной (( в начале каждого cond термина, но если вы не делаете что-то необычное, вы не должны ожидать этого где-либо еще.

При добавлении лишних круглых скобок ((display "something") #t) это интерпретируется как (display "something"), которое вернет процедуру, и что вы хотите проверить, каким станет результат этой процедуры с аргументом #t. Когда оцениваются все части, происходит сбой, поскольку затем обнаруживается, что неопределенное значение не является процедурой. Есть случаи, когда это работает:

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

Здесь вы видите, что первая часть оценивается как результат оценки -, когда x меньше нуля. Если это -10, результатом будет -11, а если это 10, применяемая процедура будет оценкой + с результатом 11.

Позже он обнаружит, что значение 3 не является процедурой, и вы получите ошибку. и чтобы получить результат, схема должна сделать (apply 3 '(#t))and it detects that 3 (in your case whatdesiplayreturns which is an unspecified value) Scheme interprets this by evaluating(display (nCr lr)`, которая печатает что-то и возвращает возвращаемое значение, которое по спецификации не определено и, следовательно, по свободному выбору разработчиков, затем применяется как процедуру из-за лишних скобок.

В Guile результат значений, не определенных в спецификации, становится синглтоном, который отображает #<unspecified> и игнорируется REPL. Вы можете найти реализацию Scheme, в которой неуказанное значение является процедурой, не принимающей аргументов, и ваша реализация будет работать безупречно, но не будет переносимой.

person Sylwester    schedule 24.06.2016
comment
Как мне решить это тогда? На что мне его поменять? - person Tarun Maganti; 24.06.2016
comment
@TarunMaganti Вы меняете его с ((display (n-C-r l r)) на (display (n-C-r l r). Если это не часть специальной формы, как в привязках let, каждый пранетезис представляет собой вызов процедуры. У вас будет то же самое в языках алгола, если вы добавите () в конце таких операторов, как somefun()(). - person Sylwester; 24.06.2016
comment
Я изменил строку следующим образом - ((и (> r 0) (‹ rl)) (display (nCr lr) (display ) (row-iter (+ r 1) ln)) Но разве синтаксис не такой, cond(‹предикат› ‹выражение›) и мне нужно было запустить несколько процедур в выражении, поэтому я использовал скобки для их группировки.Если я удалил скобки, синтаксис стал примерно таким... cond (‹предикат› ‹выражение› ‹ выражение› ‹выражение›), допустимо ли это? - person Tarun Maganti; 24.06.2016
comment
Я запустил его после изменений, и ошибка была точно такой же!? - person Tarun Maganti; 24.06.2016
comment
Я попытался ввести функцию, определенную как - (define (disp l r) (display (n-C-r l r))) и использовал ее. Я не знаю, заменяет ли Scheme функцию и интерпретирует ее или переходит к ячейке памяти, как в C/C++, но ошибка возникла даже после изменения. - person Tarun Maganti; 24.06.2016
comment
@TarunMaganti cond и явное begin, поэтому термин cond выглядит как (predicate consequent1 consequent2 ...), если бы это было не так, он выглядел бы как (predicate (begin consequent1 consequent2 ...)). У вас есть несколько мест, где у вас есть лишние скобки вокруг последствий, и не только это место, поэтому вам нужно удалить лишнее из всех мест. - person Sylwester; 25.06.2016

Ошибка, как указано Сильвестром в его ответе, заключается в выражении ((display (n-C-r l r)) (display " ") (row-iter (+ r 1) l n))). Оператор действительно интерпретирует это, оценивая ((display (n-C-r l r)), который печатает что-то и возвращает неопределенное значение и применяется как процедура, рассматривающая ((display (n-C-r l r)) как чрезмерно заключенную в скобки.

Я решил проблему с помощью Sequencing. Специальная форма begin используется для объединения нескольких операторов и возвращает значение последнего оператора. Секвенирование в MIT-Scheme. Это работало и в схеме хитрости.

Синтаксис специальной формы begin: (begin <e1> <e2> <e3>....<en>)
Возвращает возвращаемое значение выражения <en>.

Вот измененный код:

(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))
    )
)

Хотя выходные данные неправильно отформатированы как «треугольник», мы можем получить треугольник Паскаля с отступом влево после изменения кода.

Запустив ./pascalTriangle 5, мы получим результат в виде

1    
1 1    
1 2 1    
1 3 3 1    
1 4 6 4 1    
1 5 10 10 5 1
person Tarun Maganti    schedule 24.06.2016
comment
Так как cond имеет явный begin, то в качестве элементов, помимо предиката, можно просто поместить более одного следствия. Первый член будет похож на ((= r 0) (display 1) (display " ") (row-iter n (+ r 1))) - person Sylwester; 27.06.2016
comment
Вы имеете в виду неявное? Я пробовал это, но, похоже, это не сработало. :/ - person Tarun Maganti; 27.06.2016