Scheme 为什么apply map and to list of expressions只返回一个布尔值?
为什么:Scheme 为什么apply map and to list of expressions只返回一个布尔值?,scheme,racket,Scheme,Racket,为什么:(应用map和-l(gentruth 2'(#t#f)) 返回”(#f#f)?我希望它为包含布尔值对的每个子表达式返回一个布尔值。 更好的和-l程序 问题在于和-l程序的运行方式可能出乎意料。这里,x在传递到过程主体之前被放入一个列表中。考虑: scratch.rkt>(定义坏程序(lambda x)) scratch.rkt>(错误处理’(#t#f)) “(#t#f)) 人们可能会期望和-l过程测试列表是否包含所有真值,而传递到过程主体的过程会: scratch.rkt>(和-l-
(应用map和-l(gentruth 2'(#t#f))
返回”(#f#f)
?我希望它为包含布尔值对的每个子表达式返回一个布尔值。更好的
和-l
程序
问题在于
和-l
程序的运行方式可能出乎意料。这里,x
在传递到过程主体之前被放入一个列表中。考虑:
scratch.rkt>(定义坏程序(lambda x))
scratch.rkt>(错误处理’(#t#f))
“(#t#f))
人们可能会期望和-l
过程测试列表是否包含所有真值,而传递到过程主体的过程会:
scratch.rkt>(和-l-bad'(#t#f))
#t
scratch.rkt>(和-l-bad'(#f#f))
#t
scratch.rkt>(和-l-bad'(#t#t))
#t
这是和-l
的正确版本;请注意,不需要应用:
(define (cart . lists)
(cond ((null? lists) '())
((= (length lists) 1) (map list (first lists)))
(else
(append-map (lambda(x)
(map (lambda(y) (cons y x))
(first lists)))
(apply cart (rest lists))))))
(define (numbers n)
(define (reversed-numbers n)
(if (= n 0)
'()
`(,n . ,(reversed-numbers (- n 1)))))
(reverse (reversed-numbers n)))
(define (gen-truth n vals)
(apply cart (map (lambda(x) list vals) (numbers n))))
(gen-truth 2 '(#t #f)) returns: '((#t #t) (#f #t) (#t #f) (#f #f))
(define and-l (lambda x
(if (null? x)
#t
(if (car x) (apply and-l (cdr x)) #f))))
测试新程序:
scratch.rkt>(and-l'(#t#f))
#f
scratch.rkt>(and-l'(#f#f))
#f
scratch.rkt>(and-l'(#t#t))
#t
现在,和-l
正在正常工作,我们将注意力转向:
(define and-l
(lambda (x)
(if (null? x)
#t
(and (car x) (and-l (cdr x))))))
同样,这里不需要apply
。在这里执行(apply map and-l;…)
甚至没有意义。apply
过程将过程和列表作为参数,并使用列表中的元素作为过程的参数。因此,(apply+'(1234))
相当于(+1234)
。在当前环境中不需要这种能力;只需将map
应用于和-l
到gen truth
返回的列表中的每个布尔值列表:
scratch.rkt>(gen truth 2'(#t#f))
“(#t#t)(#f#t)(#t#f)(#f#f))
scratch.rkt>(map和-l(gentruth 2'(#t#f)))
“(#t#f#f#f)
打捞原始和-l
程序
请注意,和-l-bad
不适用于参数列表,而是适用于包装在列表中并传递给过程体的未指定数量的参数:
scratch.rkt>(和-l-bad#t#f#f)
#f
scratch.rkt>(和-l-bad#t#t#t)
#t
scratch.rkt>(和-l-bad#f#f#t)
#f
记住这一点,无需将和-l-bad
重写为和-l
即可实现OP目标。相反,重新思考(应用map和-l(gen truth 2'(#t#f))
:
scratch.rkt>(map(lambda(x)(apply and-l-bad x))(gen-truth 2'(#t#f)))
“(#t#f#f#f)
这里,map
将函数应用于gen truth
返回的列表中的每个布尔列表。该函数接受一个布尔列表,并将apply
与和-l-bad
一起应用于它,例如(apply和-l-bad'(#t#f)
-->(和-l-bad#t#f)
,这正是和-l-bad
所期望的
和进程
过程和-l-bad
实际上类似于和,因为它接受数量不确定的参数,并返回将参数与和组合的结果:
scratch.rkt>(和-l-bad#t#t#f#t)
#f
scratch.rkt>(和#t#t#f#t)
#f
但是有一个重要的区别:和-l-bad
是一个过程,而和
是一种特殊形式。过程总是计算所有参数,但特殊形式有特殊的计算规则。特殊形式和
依次计算其参数,直到结果已知,或者返回第一个#f
在该序列中遇到,或序列的最后一个值。这是短路评估
和-l-bad
的更好名称可能是和proc
。原始名称和-l
建议将和应用于列表(这不是真的),而和proc
强调这是一个行为类似于和的过程
为什么您首先需要像和proc
这样的东西?嗯,apply
为它的第一个参数使用一个过程,所以(map(lambda(x)(apply和x))(gen truth 2'(#t#f))
将不起作用。但是这将起作用:
scratch.rkt>(映射(lambda(x)(应用和过程x))(gen truth 2'(#t#f)))
“(#t#f#f#f)
这里我们使用了一个类似于和的过程,其中和本身不起作用。和proc
的缺点是它总是计算所有参数;这并不总是可取的
如何避免编写新的和类似的过程
在此处使用和
编写一个新的过程来处理,完全可以避免:
scratch.rkt>(映射(lambda(x)(和映射标识x))(gen truth 2'(#t#f)))
“(#t#f#f#f)
这里的(lambda(x)(andmap identity x))
是一个过程,它接受其参数并将它们与和相结合。也就是说,((lambda(x)(andmap identity x))”(#t#f))
等价于(和(identity#t)(identity#f))
。这个过程像以前一样映射到布尔列表上
这相当于本答案顶部定义的和-l
,而和-l
实际上可以更好地定义为:
(定义(和-lxs)
(和地图标识xs))
仍然无法识别何时使用apply以及在何处不需要它。如果你有一个函数,比如说3个参数,你可以像这样调用它:(func x y z)
。但是如果你将这三个参数打包在一个列表中,”(x y z)会怎么样
,但你想对这三个参数调用同一个函数吗?然后用apply
:(apply func'(x y z))
调用它。这里的答案是:@X10D--答案指出:“请不要。”
(apply map and-l (gen-truth 2 '(#t #f)))