为什么 apply map 和 to 表达式列表只返回一个布尔值? [英] why does apply map and to list of expressions returns only one boolean?

查看:49
本文介绍了为什么 apply map 和 to 表达式列表只返回一个布尔值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(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))))

为什么:(apply map and-l (gen-truth 2 '(#t #f)))

return '(#f #f) ?我希望它为每个包含布尔值对的子表达式返回一个布尔值.

return '(#f #f) ? i would expect it return a Boolean for each of the sub expressions containing pairs of Boolean values.

推荐答案


更好的and-l程序

<小时>

问题在于 and-l 过程的运行方式可能出乎意料.这里, x 在传递到过程主体之前被放入一个列表中.考虑:


A Better and-l Procedure


The problem is that the and-l procedure is operating in a way that probably was not anticipated. Here, x is put into a list before being passed along to the body of the procedure. Consider:

scratch.rkt> (define bad-proc (lambda x x))
scratch.rkt> (bad-proc '(#t #f))
'((#t #f))

人们可能会期望 and-l 过程来测试列表是否包含所有真值,而传递给过程主体的则是:

One would probably expect the and-l procedure to test whether a list contains all true values, and the one passed to the body of the procedure does:

scratch.rkt> (and-l-bad '(#t #f))
#t
scratch.rkt> (and-l-bad '(#f #f))
#t
scratch.rkt> (and-l-bad '(#t #t))
#t

这是and-l的正确版本;注意不需要apply:

Here is a correct version of and-l; note that there is no need for apply:

(define and-l
  (lambda (x)
    (if (null? x)
        #t
        (and (car x) (and-l (cdr x))))))

测试新程序:

scratch.rkt> (and-l '(#t #f))
#f
scratch.rkt> (and-l '(#f #f))
#f
scratch.rkt> (and-l '(#t #t))
#t

既然 and-l 正常工作,我们将注意力转向:

Now that and-l is working as it should, we turn our attention to:

(apply map and-l (gen-truth 2 '(#t #f)))

同样,这里不需要apply.在这里执行 (apply map and-l ;....) 甚至没有任何意义.apply 过程将过程和列表作为参数,并使用列表的元素作为过程的参数.所以,(apply + '(1 2 3 4)) 等价于 (+ 1 2 3 4).在当前上下文中不需要此功能;所需要的只是 mapand-l 应用到 gen-truth 返回的列表中的每个布尔值列表:

Again, there is no need for apply here. It does not even make sense here to do (apply map and-l ;....). The apply procedure takes a procedure and a list as arguments, and uses the elements of the list as arguments to the procedure. So, (apply + '(1 2 3 4)) is equivalent to (+ 1 2 3 4). This capability is not needed in the current context; all that is needed is map to apply and-l to each list of booleans in the list returned by gen-truth:

scratch.rkt> (gen-truth 2 '(#t #f))
'((#t #t) (#f #t) (#t #f) (#f #f))
scratch.rkt> (map and-l (gen-truth 2 '(#t #f)))
'(#t #f #f #f)

<小时>

挽救原来的and-l程序

<小时>

请注意,and-l-bad 不适用于参数列表,而是适用于包装在列表中并传递给过程主体的未指定数量的参数:


Salvaging the Original and-l Procedure


Note that and-l-bad works not on a list of arguments, but on an unspecified number of arguments which are wrapped in a list and passed to the procedure body:

scratch.rkt> (and-l-bad #t #f #f)
#f
scratch.rkt> (and-l-bad #t #t #t)
#t
scratch.rkt> (and-l-bad #f #f #t)
#f

考虑到这一点,无需将 and-l-bad 如上所述重写为 and-l 即可实现 OP 目标.相反,重新思考 (apply map and-l (gen-truth 2 '(#t #f))):

With this in mind, OP goal can be achieved without rewriting and-l-bad to and-l as above. Instead, rethink (apply map and-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 返回的列表中的每个布尔列表.该函数采用一个布尔列表并将 applyand-l-bad 应用于它,例如(apply and-l-bad '(#t #f) --> (and-l-bad #t #f),这正是和-l-bad 期待.

Here, map applies a function to each boolean list in the list returned by gen-truth. That function takes a boolean list and applies apply with and-l-bad to it, so that,e.g. (apply and-l-bad '(#t #f) --> (and-l-bad #t #f), which is exactly what and-l-bad is expecting.

过程 and-l-bad 真的很像 and,因为它接受未指定数量的参数并返回参数与 组合的结果和:

The procedure and-l-bad is really like and, in that it takes an unspecified number of arguments and returns the result of combining the arguments with and:

scratch.rkt> (and-l-bad #t #t #f #t)
#f
scratch.rkt> (and #t #t #f #t)
#f

但是有一个重要的区别:and-l-bad是一个过程,而and是一个特殊形式.过程总是评估所有的参数,但特殊形式有特殊的评估规则.特殊形式 and 依次计算其参数,直到知道结果为止,要么返回该序列中遇到的第一个 #f,要么返回该序列的最后一个值.这是短路评估.

But there is an important difference: and-l-bad is a procedure, while and is a special form. Procedures always evaluate all of their arguments, but special forms have special evaluation rules. The special form and evaluates its arguments sequentially until the result is known, either returning the first #f encountered in that sequence, or the last value of the sequence. This is short-circuit evaluation.

and-l-bad 的更好名称可能是 and-proc.原始名称 and-l 表明 and 被应用于列表(这是不正确的),而 and-proc 强调这是一个过程,其行为类似于.

A better name for and-l-bad would perhaps be and-proc. The original name, and-l suggested that and was applied to a list (which was not true), while and-proc emphasizes that this is a procedure which behaves similarly to and.

为什么首先需要像 and-proc 这样的东西?好吧,apply 为其第一个参数采用一个过程,所以 (map (lambda (x) (apply and x)) (gen-truth 2 '(#t #f))) 将不起作用.但这会起作用:

Why would you need something like and-proc in the first place? Well, apply takes a procedure for its first argument, so (map (lambda (x) (apply and x)) (gen-truth 2 '(#t #f))) will not work. But this will work:

scratch.rkt> (map (lambda (x) (apply and-proc x)) (gen-truth 2 '(#t #f)))
'(#t #f #f #f)

这里我们使用了一个 and 类似的 procedure,其中 and 本身不起作用.and-proc 的缺点是它总是对 all 的参数求值;这并不总是可取的.

Here we have used an and-like procedure where and itself would not work. The downside of and-proc is that it always evaluates all of its arguments; this is not always desirable.

在这里可以完全避免使用 编写一个新程序来处理:

Writing a new procedure to handle using and here could have been avoided altogether:

scratch.rkt> (map (lambda (x) (andmap identity x)) (gen-truth 2 '(#t #f)))
'(#t #f #f #f)

这里的(lambda (x) (andmap identity x)) 是一个过程,它接受它的参数并将它们与and 组合起来.即 ((lambda (x) (andmap identity x)) '(#t #f)) 等价于 (and (identity #t) (identity #f)).这个过程像以前一样映射到布尔列表的列表上.

Here (lambda (x) (andmap identity x)) is a procedure that takes its arguments and combines them with and. That is, ((lambda (x) (andmap identity x)) '(#t #f)) is equivalent to (and (identity #t) (identity #f)). This procedure is mapped over the list of boolean lists as before.

这等价于本答案顶部定义的 and-l,并且 and-l 实际上可以更好地定义为:

This is equivalent to the and-l defined at the top of this answer, and and-l could in fact be better-defined as:

(define (and-l xs)
  (andmap identity xs))

这篇关于为什么 apply map 和 to 表达式列表只返回一个布尔值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆