【问题标题】:Using AND with the apply function in Scheme在 Scheme 中使用 AND 和 apply 函数
【发布时间】:2008-12-22 23:32:36
【问题描述】:

为什么以下方法不起作用?

(apply and (list #t #t #f))

虽然以下工作正常。

(apply + (list 1 3 2))

R5RS 和 R6RS 似乎都是这种情况?

【问题讨论】:

    标签: scheme


    【解决方案1】:

    and 不是一个普通函数,因为它只会根据需要评估尽可能少的参数,以了解结果是真还是假。例如,如果第一个参数为假,那么无论其他参数是什么,结果都必须为假,因此它不会评估其他参数。如果and 是一个普通函数,它的所有参数都将首先被计算,所以and 被设置为一个特殊的关键字,这就是它不能作为变量传递的原因。

    【讨论】:

    • 这是我对 Scheme 最大的不满之一——宏应该是一流的。我意识到它可能会阻止一些编译优化,但它肯定会增加语言的表达能力。
    • Kyle,你可能在谈论一种叫做Kernel 的语言。内核旨在解决第二类特殊形式的问题,引入其他抽象原语以提供更灵活的评估语义。 (正如你所说,编译优化可能是一个问题。)这个问题的示例and 甚至是klisp implementation's homepage 上显示的“hello world”示例。
    【解决方案2】:
    (define and-l (lambda x 
        (if (null? x)
            #t
            (if (car x) (apply and-l (cdr x)) #f))))
    

    请注意这是 lambda variadic! 应用示例(and-l #t #t #f)

    或者您可以通过应用程序使用它(如前所述) 例如(apply and-l (list #t #t #f))

    两个选项都可以...

    【讨论】:

      【解决方案3】:

      and 实际上是一个宏,其定义在in R5RS chapter 4 中概述。该页面上的符号“库语法”实际上意味着它是作为宏实现的。

      7.3, Derived expression types 部分给出了and 宏的可能定义:

      (define-syntax and
        (syntax-rules ()
          ((and) #t)
          ((and test) test)
          ((and test1 test2 ...)
           (if test1 (and test2 ...) #f))))
      

      鉴于此定义,不可能将and 用作apply 的函数参数。

      【讨论】:

        【解决方案4】:

        在Scheme方言MIT/GNU Scheme中,您可以使用the function boolean/and代替the special form and

        (apply boolean/and (list #t #t #f)) ;Value: #f
        

        另外,作为记录,我在Guile Schemeprocedure index 中找不到任何等效函数。

        (其他答案已经解释了为什么特殊形式and 不起作用,并展示了如果您的方言中还没有这样的函数,如何编写自己的替换函数。)

        【讨论】:

          【解决方案5】:

          如果你真的想要一个函数指针指向一个执行 and 的函数,并且你不介意与“真实”and 不同的行为,那么这将起作用:

          (define and-l (lambda (a b) (and a b)))
          

          你可以这样申请:

          (apply and-l (list #t #f))
          

          两个注意事项是:

          1. 所有 args 都被评估,违反了 and 的定义,应该有快捷行为。
          2. 只允许两个参数。

          【讨论】:

          • (define (and/f . xs) (cond ((null? xs) #t) ((null? (cdr xs)) (car xs)) (else (and (car xs) (apply and/f (cdr xs))))))
          【解决方案6】:

          我偶然发现了同样的问题,并在 Racket 中找到了一个优雅的解决方案。 由于问题是“and”是一个宏而不是一个函数,以防止对其所有参数的评估,我读了一些关于“lazy racket”的文章,发现“and”是 中的一个函数那种语言。所以我想出了以下解决方案,我只导入惰性并作为“惰性和”:

          #lang racket
          (require (only-in lazy [and lazy-and]))
          
          (define (mm)
            (map number? '(1 2 3)))
          
          (printf "~a -> ~a\n" (mm) (apply lazy-and (mm)))
          

          产生

          (#t #t #t) -> #t
          

          【讨论】:

            【解决方案7】:

            试试这个:

            (define list-and (lambda (args) (and (car args) (list-and (cdr args)))))
            

            然后您可以使用 apply 来列出 - 和!

            【讨论】:

            • 这不会按预期工作。试试这个: (define (list-and args) (if (null?args) #t (and (car args) (list-and (cdr args))))))
            【解决方案8】:

            你也可以使用

            (define (andApply lBoo) (if (not (car lBoo)) #f (if (= 1(length lBoo)) (car lBoo) (andApply (cdr lBoo)))))

            【讨论】:

              【解决方案9】:

              我在使用 PLT-Scheme 372 时也遇到了这个问题,我已经深入研究了 and-syntax 的行为,并找出了下面的代码,它的工作原理就像人们直观地期望 (apply and lst) 返回一样,但我没有做过详尽的测试。

              (define (list-and lst) 
                (cond 
                  ((null? lst) '())
                  ((not (pair? lst)) (and lst)) 
                  ((eq? (length lst) 1) (car lst))
                  (else
                   (and (car lst)
                        (list-and (cdr lst))))
                  )
                )
              
              Welcome to DrScheme, version 372 [3m].
              Language: Textual (MzScheme, includes R5RS).
              
              > (eq? (and '()) (list-and '()))
              #t
              > (eq? (and '#f) (list-and (list '#f)))
              #t
              > (eq? (and 'a) (list-and (list 'a)))
              #t
              > (eq? (and 'a 'b) (list-and (list 'a 'b)))
              #t
              > (eq? (and 'a 'b '()) (list-and (list 'a 'b '())))
              #t
              > (eq? (and 'a 'b '#t) (list-and (list 'a 'b '#t)))
              #t
              > (eq? (and 'a 'b '#f) (list-and (list 'a 'b '#f)))
              #t
              

              我还想出了另一种令人费解的解决方法。我称它为mind-trapping,因为一开始我不知道如何把它变成一个函数......这里是(只是我的直觉想法的一个演示):

              Welcome to DrScheme, version 372 [3m].
              Language: Textual (MzScheme, includes R5RS).
              > (eval (cons 'and (list ''#f ''#f ''#t)))
              #f
              > (eval (cons 'and (list ''a ''b ''c)))
              c
              

              但后来我问了一个问题,在这里得到了答案:Is it possible to generate (quote (quote var)) or ''var dynamically?。有了这个答案,我们可以很容易地将上面的想法变成一个函数。

              (define (my-quote lst)
                (map (lambda (x) `'',x) lst))
              
              (cons 'and (my-quote (list 'a 'b 'c)))
              => '(and ''a ''b ''c)
              

              【讨论】:

              • 使用eval 太过分了,不推荐。在 Racket 中,您可以使用 andmap 来执行此操作:(andmap values '(a b c)) => c。 (在 Racket 中,您也可以使用 identity 代替 values。)
              • 感谢您分享andmapidentity ...您的意思是“eval ...”对于诸如将“和”映射到“列表”这样的简单任务来说太强大了,出现问题后我无法控制它? (无论如何,我会记住你的建议!)
              • eval 被滥用得太频繁了,如果您没有正确引用所有内容,可能会导致安全问题。对于您在这里所做的事情来说,它也太重量级了。对我来说,eval 的主要用途是运行用户提供的代码(伴随着运行用户提供的代码的所有安全隐患),例如在 REPL 中。
              • 听起来eval 超出了我的理解范围,至少目前如此。我会避免用它来取乐……除非我对它有信心。 :)
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-01-16
              • 1970-01-01
              • 2020-02-06
              • 2023-03-08
              • 2022-01-10
              • 1970-01-01
              相关资源
              最近更新 更多