方案出错 "The object (unquote f), passed as an argument to identifier->symbol, is not an identifier."
Getting error in scheme "The object (unquote f), passed as an argument to identifier->symbol, is not an identifier."
我正在尝试实现一个函数 composex
给定一个函数列表 funcs
returns 一个函数是 funcs
中所有函数的组合
所以,
input -> [f1 f2 f3 ...]
output -> 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 执行。
轻松修复,IIUC:您在内部 lambda
的参数列表中放置了一个逗号。拿出来。
逗号在Scheme中有特殊含义;它允许您从准报价中 "escape"。在这种情况下,您没有使用准引号,因此此处的逗号在 Scheme 中没有任何意义。
不过,这是一条非常糟糕的错误消息。
本部分:
(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)
就像 '
一样,这些由 reader 宏处理。因此就像 'x
是 (quote x)
,`(,x)
与 (quasiquote ((unquote x)))
和 quote
相同,quoasiquote
和 unquote
是特殊形式.你的兰巴最终看起来像:
(lambda (ini (unquote f)) (f x))
MIT Scheme 不支持可选参数,只有像 ini
和 f
这样的符号可以出现在 lamba 列表中,而不是列表 (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,那么生成的函数可以使用零参数,并且使用多个 arity 一个它变成一个 multi arity 函数:
(define double+ (compose double +))
(double+ 3 8 9 2)
; ==> 44
潜在问题
如@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
这是因为你的减速器忽略了 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
我正在尝试实现一个函数 composex
给定一个函数列表 funcs
returns 一个函数是 funcs
中所有函数的组合
所以,
input -> [f1 f2 f3 ...]
output -> 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 执行。
轻松修复,IIUC:您在内部 lambda
的参数列表中放置了一个逗号。拿出来。
逗号在Scheme中有特殊含义;它允许您从准报价中 "escape"。在这种情况下,您没有使用准引号,因此此处的逗号在 Scheme 中没有任何意义。
不过,这是一条非常糟糕的错误消息。
本部分:
(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)
就像 '
一样,这些由 reader 宏处理。因此就像 'x
是 (quote x)
,`(,x)
与 (quasiquote ((unquote x)))
和 quote
相同,quoasiquote
和 unquote
是特殊形式.你的兰巴最终看起来像:
(lambda (ini (unquote f)) (f x))
MIT Scheme 不支持可选参数,只有像 ini
和 f
这样的符号可以出现在 lamba 列表中,而不是列表 (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,那么生成的函数可以使用零参数,并且使用多个 arity 一个它变成一个 multi arity 函数:
(define double+ (compose double +))
(double+ 3 8 9 2)
; ==> 44
潜在问题
如@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
这是因为你的减速器忽略了 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