mcdr: ожидается нарушение договора: mpair? дано: 5 - PullRequest
0 голосов
/ 21 февраля 2020

Я пишу программу в схеме, которая принимает обычную схему, например: (* 5 6) и возвращает нотацию, которую вы использовали бы на любом другом языке, например: (5 * 6)

У меня есть мой рекурсивный шаг вниз, но у меня возникают проблемы с выходом в базовый случай.


(define (infix lis)
  (if (null? lis) '()
      (if (null? (cdr lis)) '(lis)
       (list (infix (cadr lis)) (car lis) (infix(caddr lis))))))

(infix '(* 5 6))

ошибка возникает при (if (null? lis)) '(lis)

ошибке сообщение:

 mcdr: contract violation
  expected: mpair?
  given: 5
> 

почему оно дает мне ошибку и как я могу это исправить?

Ответы [ 2 ]

2 голосов
/ 22 февраля 2020

В данный момент ваша функция infix предполагает, что ее входные данные всегда являются списком. Входные данные не всегда являются списком: иногда это число.

A PrefixMathExpr is one of:
 - Number
 - (list BinaryOperation PrefixMathExpr PrefixMathExpr)

Если это структура ваших данных, код должен следовать этой структуре. Определение данных имеет единичное значение, поэтому код должен иметь условное выражение.

;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
  (cond
    [(number? p) ???]
    [(list? p)   ???]))

Каждая условная ветвь может использовать части из этого случая определения данных. Здесь ветвь списка может использовать (car p), (cadr p) и (caddr p).

;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
  (cond
    [(number? p) ???]
    [(list? p)   (.... (car p) (cadr p) (caddr p) ....)]))

Некоторые из этих подразделов являются сложными определениями данных, в данном случае это собственные ссылки на PrefixMathExpr , Эти самореференции естественным образом превращаются в рекурсивные вызовы:

;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
  (cond
    [(number? p) ???]
    [(list? p)   (.... (car p) (infix (cadr p)) (infix (caddr p)) ....)]))

Затем заполните дыры.

;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
  (cond
    [(number? p) p]
    [(list? p)   (list (infix (cadr p)) (car p) (infix (caddr p)))]))

Этот процесс для построения структуры программы на основе структуры данных происходит из Как разрабатывать программы .

1 голос
/ 22 февраля 2020

Ошибка

(infix '(* 5 6))
; = 
(list (infix (cadr '(* 5 6))) (car '(* 5 6)) (infix (caddr '(* 5 6))))
; = 
(list (infix 5) '* (infix (caddr 6)))
; =   ^^^^^^^^^
;        |
;        |
;        v
(if ...
 ...
 (if (null? (cdr 5)) ; <-- fails here
     ...
     ...))

Решение

Сначала необходимо определить структуру данных, которыми вы манипулируете:

; OpExp is one of:
; - Number
; - (cons Op [List-of OpExp])

; Op = '+ | '* | ...

В английском sh: это либо число, либо оператор, за которым следует список других выражений.

Определим несколько примеров:

(define ex1 7)
(define ex2 '(* 1 2))
(define ex3 `(+ ,ex2 ,ex1))
(define ex4 '(* 1 2 3 (+ 4 3 2) (+ 9 8 7)))

Теперь мы следуем структуре OpExp, чтобы создать «шаблон»:

(define (infix opexp)
  (if (number? opexp)
      ... 
      (... (car opexp) ... (cdr opexp) ...)))

Два случая:

  • Первый случай: что делать, когда мы просто получаем число?
  • Второй случай: сначала извлечь компонент enet:
    • (car opexp) является оператором
    • (cdr opexp) - список операндов типа OpExp

Уточнение шаблона:

(define (infix opexp)
  (if (number? opexp)
      opexp
      (... (car opexp) ... (map infix (cdr opexp)) ...)))

Поскольку у нас есть список Операторы, нам нужно отобразить рекурсивный вызов для всех из них. Все, что нам нужно сделать, это сделать оператор инфиксом на верхнем уровне.

Мы используем помощника, который переплетает список с оператором:

; inserts `o` between every element in `l`
(define (insert-infix o l)
  (cond ((or (null? l) (null? (cdr l))) l) ; no insertion for <= 1 elem lst
        (else (cons (car l) (cons o (insert-infix o (cdr l)))))))

и, наконец, используем помощника для получения окончательной версии:

; converts OpExp into infix style
(define (infix opexp)
  (if (number? opexp)
      opexp
      (insert-infix (car opexp) (map infix (cdr opexp)))))

Мы определяем соответствующие результаты для наших примеров:

(define res1 7)
(define res2 '(1 * 2))
(define res3 `(,res2 + ,res1))
(define res4 '(1 * 2 * 3 * (4 + 3 + 2) * (9 + 8 + 7)))

И вызов infix на ex1 ... exN должен привести к res1 ... resN

...