在方案中获得错误“作为参数传递给identifier->符号的对象(unquote f)不是标识符。”

时间:2018-05-17 16:11:18

标签: lambda functional-programming scheme function-composition mit-scheme

我正在尝试实现一个函数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.

我正在使用mit-scheme执行。

3 个答案:

答案 0 :(得分:3)

轻松修复,IIUC:您在内部lambda的参数列表中添加了逗号。拿出来。

逗号在Scheme中具有特殊含义;它允许你从quasiquote“逃脱”。在这种情况下,你不使用quasiquote,所以这里的逗号在Scheme中没有任何意义。

但这是一个非常糟糕的错误信息。

答案 1 :(得分:3)

潜伏着问题

正如@John所说,您需要移除,中的(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

这是因为您的reducer忽略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来定义合成。请注意使用quasiquote `

(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

答案 2 :(得分:1)

在这部分:

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

现在我不确定您是否错误地将参数分隔为,或某些疯狂的重合符ini,作为参数的名称,但是,用于quasiquote表达式:

(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相同,quoasiquoteunquote是特殊形式。你的lamba最终看起来像:

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

MIT Scheme不支持可选参数,只有像inif这样的符号可以在lamba列表中而不是列表(unquote f)。因此,您需要将其更改为:

(lambda (ini f) (f x))

修改

您的reducexfoldl相同,除了它中的参数顺序和所需的函数。例如

(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的顺序完成的,那么答案就是200compose支持最正确的函数的arity,因此首先应用它。如果它是一个thunk,那么结果函数是零参数和多个arity,它就变成了一个多元函数:

(define double+ (compose double +))
(double+ 3 8 9 2)
; ==> 44