Получение ошибки в схеме «Объект (без кавычки f), переданный в качестве аргумента идентификатору-> символу, не является идентификатором». - PullRequest
0 голосов
/ 17 мая 2018

Я пытаюсь реализовать функцию composex, которая с учетом списка функций funcs возвращает функцию, которая является композицией всех функций в funcs Таким образом,

ввод -> [f1 f2 f3 ...]
вывод -> f '(x) = f1 (f2 (f3 (... (x))))

Фрагмент кода, который у меня есть:

(define (reducex initial f arr)
  (if (null? arr)
    initial
    (reducex (f initial (car arr))
      f
      (cdr arr)
    )
  )
)


(define (abst x)
  (if (< x 0)
    (- x)
    x
  )
)

(define (mult2 x)
  (* x 2))

(define (composex funcs)
  (lambda (x)
    (reducex '()
      (lambda (ini, f) (f x))
      funcs)
  )
)

(define absmult2 (composex (cons abst (cons mult2 '()))))
(absmult2 2)
(absmult2 -2)

Я получаю ошибку в composex

;The object (unquote f), passed as an argument to identifier->symbol, is not an identifier.
;To continue, call RESTART with an option number:
; (RESTART 1) => Return to read-eval-print level 1.

Я использую мит-схему для исполнения.

Ответы [ 3 ]

0 голосов
/ 17 мая 2018

В этой части:

(lambda (ini, f) (f x))

Теперь я не уверен, что вы по ошибке разделили аргументы на , или по какому-то безумному совпадению хотели, чтобы ini, было именем параметра, но , используется в выражениях квазиквот:

(define a 10)
(define b 20)
`(list with ,a and ,(+ a b) inserted) 
; ==> (list with 10 and 30 inserted)

Как и ', они обрабатываются макросами читателя.Таким образом, точно так же, как 'x является (quote x), `(,x) совпадает с (quasiquote ((unquote x))), а quote, quoasiquote и unquote являются специальными формами.Ваша лямба в итоге выглядит так:

(lambda (ini (unquote f)) (f x))

Схема MIT не поддерживает необязательные аргументы, только символы, такие как ini и f, могут быть в списке ламбы, а не в списке (unquote f).Таким образом, вам нужно изменить его на:

(lambda (ini f) (f x))

РЕДАКТИРОВАТЬ

Ваш reducex такой же, как foldl за исключением порядка аргументов в нем ифункция, которую он принимает.например.

(fold cons '() '(1 2 3))    ; ==> (3 2 1)
(reducex '() (lambda (a e) (cons e a)) '(1 2 3)) ; ==> (3 2 1)

Ваш compose выполняет приложение в неправильном порядке, и такая функция обычно принимает переменное число аргументов.например.

((compose - +) 3 5)
; ==> -8

Вот что я думаю, что вам нужно сделать:

(define (compose . funcs)
  (case (length funcs)
    ((0) (lambda (v) v)) ; identity
    ((1) (car funcs))    ; return the argument
    (else                ; return a composition
     (let* ((rfuncs (reverse funcs))
            (initial-func (car rfuncs))
            (rest-funcs (cdr rfuncs))
            (reduce (lambda (fn a) (fn a))))
       (lambda args
         (foldl reduce
                (apply initial-func args)
                rest-funcs))))))

Итак, давайте проверим это с чем-то, где порядок имеет значение:

(define (add100 v) (+ v 100))
(define (double v) (* v 2))

(define (manual-compose v)
  (double (add100 v)))

(define test-compose (compose double add100))

(manual-compose 50)
; ==> 300
(test-compose 50)
; ==> 300

Если бы композиция быласделано в порядке вашего composex ответ будет 200.compose поддерживает арность самой правой функции, то есть той, которая должна быть применена первой.Если это thunk, то результирующая функция в порядке с нулевыми аргументами и с множественной арностью один, она становится многоартериальной функцией:

(define double+ (compose double +))
(double+ 3 8 9 2)
; ==> 44 
0 голосов
/ 17 мая 2018

скрывающиеся проблемы

Как заметил @Джон, вам нужно удалить , в (ini, f) и изменить на (ini f).Это приводит к синтаксически правильной программе, но другие проблемы сохраняются.

Я бы порекомендовал внести изменения в вашу compose процедуру.Во-первых, начальная '() неверна, потому что она не соответствует типу функции.Вы получите странный результат, если попытаетесь применить аргумент к пустой композиции

(define (composex funcs)
  (lambda (x)
    (reducex '()
             (lambda (ini f) (f x))
             funcs)))

(define foo (composex '()))
(foo 'x) ; => '()

Во-вторых, ваш редуктор (lambda (ini f) (f x)) неверен, поэтому вы получаете неправильные ответы

(absmult2 2) ; 4
(absmult2 -2) ; -4

Это потому, что ваш редуктор игнорирует ini.Это фактически то, что происходит, когда мы вызываем (absmult2 -2)

(let ((ini '()))
  (set! ini (abst -2))
  (set! ini (mult2 -2))
  ini) ;; -4

На самом деле нам нужно поведение

(let ((ini -2))
  (set! ini (abst ini))
  (set! ini (mult2 ini))
  ini) ;; 4

Мы можем исправить эти две проблемы одновременно, переработав composex

(define (composex funcs)
  (lambda (ini)
    (reducex ini
             (lambda (x f) (f x))
             funcs)))

(absmult2 2) ; 4
(absmult2 -2) ; 4

Теперь это работает и для пустых композиций

(define foo (composex '()))
(foo 'z) ; 'z

помогая себе

По иронии судьбы, ошибка, которую вы сделали изначально, может быть использованав другом месте, чтобы улучшить читаемость вашего кода.Вы можете использовать запятую без кавычек , вместо cons, чтобы определить свою композицию.Обратите внимание на использование квазицитата `

(define absmult2 (composex `(,abst ,mult2)))

(absmult2 2)  ; 4
(absmult2 -2) ; 4

В качестве альтернативы, вы можете изменить composex, чтобы он принимал переменное количество входных данных

(define (composex . funcs)
  (lambda (ini)
    (reducex ini
             (lambda (x f) (f x))
             funcs)))

(define absmult2 (composex abst mult2))

(absmult2 2)  ; 4
(absmult2 -2) ; 4

латеральное мышление

Рассмотрите эти другие реализации composex как способ пощекотать ваш мозг

(define (composex . fs)
  ;; simplified composition of two functions
  (define (comp f g)
    (lambda (x) (g (f x))))
  ;; results in simplified reduce
  (reducex identity comp fs))

(define absmult2 (composex abst mult2))

(absmult2 2)  ; 4
(absmult2 -2) ; 4

Выше, как это composex обрабатываетпустой пример композиции, о котором мы говорили?

А тот, который даже не использует reduce - обратите внимание, что последний не позволяет программисту создать пустую композицию

(define (composex f . fs)
  (lambda (x)
    (if (null? fs)
        (f x)
        ((apply composex fs) (f x)))))

(define absmult2 (composex abst mult2))

(absmult2 2)  ; 4
(absmult2 -2) ; 4
0 голосов
/ 17 мая 2018

Easy fix, IIUC: вы помещаете запятую в список параметров для вашего внутреннего lambda. Возьми это.

Запятая имеет особое значение в Схеме; это позволяет вам «убежать» от квазицитаты. В этом случае вы не используете квазицитатуру, поэтому запятая здесь не имеет никакого смысла в схеме.

Это довольно ужасное сообщение об ошибке.

...