【问题标题】:can if be a proper function rather than a special form可以是一个适当的函数而不是一个特殊的形式
【发布时间】:2011-01-15 11:51:34
【问题描述】:

我终于开始学习函数式语言(emacs lisp),它明确区分了函数和特殊形式,例如流控制,例如 if。

特殊形式与函数不同是否有基本/理论原因?是否有任何语言提供功能性if

谢谢

【问题讨论】:

标签: function lisp functional-programming special-form


【解决方案1】:

使用热切评估需要区分,具有惰性评估的语言(即 Haskell)if 等。可以是函数。

急切评估:函数的参数在调用函数之前被评估,并且只有结果被传递给函数。

惰性求值:当且仅当函数的参数被访问时才求值。

【讨论】:

  • 好吧,我从来没有在 Scala 中做过任何事情,所以我不知道任何细节。不过,我希望人们必须指定一个参数是否被懒惰地评估——或者按名称调用是否有其他语义?如果是的话,如果你能在纯参考旁边提供一个链接,我将非常感激。
  • 我认为底层属性是纯功能性的:在纯功能性语言中,或者在仅使用纯函数(返回值但没有副作用的函数)的代码中,if 可以是一个函数。 Haskell 的惰性求值对于其功能纯度是必要的。
  • 好吧,我总是将“纯功能”中的 pure 与“没有副作用”(除了 I/O 部分......)联系起来。我从来没有想过对于纯函数式语言需要惰性求值。好吧,只是我编程地图上的另一个空白……不知何故,我开始考虑放弃所有这些问题。
【解决方案2】:

如果 if 是一个普通函数,那么它的两个参数——then 形式else 形式——都将被计算 both 调用if函数之前,因为这是function evaluation的规则:评估所有参数以产生值,然后将该值序列作为参数提供给指定的函数按列表中的第一个符号。

相反,对于if,您想要做的是准确评估 then 形式else 形式 之一,而不是两者。为了抑制对其中一个的评估,您需要一个宏或一个special form

【讨论】:

    【解决方案3】:

    在 Emacs Lisp 和 Common Lisp 等语言中,特殊形式是内置的语言结构。它们具有正常函数调用的不同评估规则。对于正常的函数调用,所有参数都被评估。因此,您不能将 IF 编写为普通函数 - 条件确定评估哪个子句。通常你也不能编写自己的特殊形式——在 Common Lisp 中没有用于定义特殊形式的语言结构(尽管个别实现必须以某种方式实现现有的。这导致宏。使用宏,你可以编写句法转换将一个表达式转换为另一个表达式。为了能够将 IF 编写为宏,您需要有另一种条件形式,您可以将其用于转换后的代码。Lisp 提供条件作为基本结构。假设 COND 是这样一个基本结构,那么您可以将 IF 扩展为 COND 的用法。

    MY-IF 作为 Common Lisp 中的宏:

    (defmacro my-if (condition true-clause false-clause)
       `(cond (,condition ,true-clause)
              (t ,false-clause)))
    

    所以

    (my-if (foo-p) 'one 'two)
    

    扩展为

    (cond ((foo-p) 'one)
          (t 'two))
    

    【讨论】:

      【解决方案4】:

      为了完整性:例如,Pico 语言中没有特殊形式,if 是一个原始函数,而 Pico 受 ​​Scheme 的启发,默认情况下具有渴望评估。 p>

      在Scheme中你可以写

      (define (true t f)
        (t))
      
      (define (false t f)
        (f))
      
      (define (function_if c t e)
        (c t e))
      

      然后

      (function_if true (lambda () 'true) (lambda () 'false))
      ==> true
      

      在 Pico 中实现这一点的原因在于您可以定义功能参数,这些参数采用“自动”延迟的功能参数。这意味着您不必自己在 lambdas 中进行包装。因此,Pico 具有热切求值,但需要根据需要进行惰性求值,从而绕过了对特殊形式的需求。

      因此,在带有函数参数的 Scheme 语法中,您可以将布尔值编码为:

      (define (true (t) (f))
        (t))
      
      (define (false (t) (f))
        (f))
      

      如果变为:则函数:

      (define (function_if c (t) (e))
        (c (t) (e)))
      

      (function_if true 'true 'false)
      ==> true
      

      再举一个例子,函数and的定义是(define (and p (q)) (p (q) false))

      同样,您可以使用上述布尔编码将ornotwhilefor...定义为函数。

      【讨论】:

        【解决方案5】:

        简短回答:不。

        Long(er) answer: (if ...) 要求您控制参数的评估顺序。 Lisp,作为一种热切的语言,无法在函数中做到这一点。

        解决方法:在宏中执行:

        (defmacro _if (cnd true false)
            (let (  (gcond (gensym))
                    (gresp (gensym)))
                `(let ( (,gcond ,cnd) ;`#quotes
                        (,gresp nil))        
                    (and ,gcond       (setf ,gresp (multiple-value-list ,true)))
                    (and (not ,gcond) (setf ,gresp (multiple-value-list ,false)))
                    (values-list ,gresp))))
        

        例如:

        [dsm@localhost:~]$ clisp -q
        [1]> (defmacro _if (cnd true false)
            (let (  (gcond (gensym))
                    (gresp (gensym)))
                `(let ( (,gcond ,cnd) ;`#quotes
                        (,gresp nil))        
                    (and ,gcond       (setf ,gresp (multiple-value-list ,true)))
                    (and (not ,gcond) (setf ,gresp (multiple-value-list ,false)))
                    (values-list ,gresp))))
        _IF
        [2]> (_if (= 1 1) (+ 2 3) "bar")
        5
        [3]> (_if (= 1 2) (+ 2 3) "bar")
        "bar"
        [4]> 
        

        【讨论】:

        • 我认为在 ANSWER 中发布工作代码会有所帮助。不仅代码的语法被破坏,逻辑也被破坏。
        • 逻辑没有缺陷。 (and ...) 和 (or ...) 已经很懒惰了。语法破坏了。
        • 为什么 (_if t nil 3) 返回 3?
        • 为什么 (let ((cond nil)) (_if cond t nil)) 返回 T?
        • 在我看来,您的 OR/AND 逻辑根本不起作用。 (_if t nil 'false) 返回 false 而不是 NIL。我会说,一个不起作用的基本 IF 就是没有 IF。
        【解决方案6】:

        在 Scala 中,可以使用按名称调用的参数对 if 进行正确的副作用评估。

        def If[A](cond : Boolean, truePart : => A, falsePart : => A) = if (cond) truePart else falsePart
        

        这些功能也可用于模拟大量new control structures

        【讨论】:

          【解决方案7】:

          IF 可以是具有按名称调用语义(惰性求值)的函数式语言中的函数,例如 Lambda Calculus 或 Algol。事实上,我认为,Turing Machines and Lambda Calculus 之间关系的核心是计算的等效基础。但是,在具有副作用的语言中(例如对变量的赋值),它并没有多大用处,因为 何时 事情发生很重要。

          【讨论】:

            猜你喜欢
            • 2016-02-01
            • 2016-07-31
            • 2016-07-08
            • 1970-01-01
            • 2020-12-16
            • 1970-01-01
            • 2019-12-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多