是否能够声明Lisp函数';纯';有益吗?

是否能够声明Lisp函数';纯';有益吗?,lisp,computer-science,compiler-optimization,proof,purely-functional,Lisp,Computer Science,Compiler Optimization,Proof,Purely Functional,我最近读了很多关于函数式语言的文章,以及它作为一种纯函数式语言所带来的好处。(我对讨论Lisp的monad不感兴趣)尽可能(至少在逻辑上)隔离具有副作用的函数对我来说是有意义的。我已经使用了大量的setf和其他破坏性函数,并且我认识到在Lisp及其(大多数)派生语言中需要它们 我们开始: 像(declare pure)这样的东西是否有助于优化编译器?或者这是一个没有实际意义的观点,因为它已经知道了 声明是否有助于证明函数或程序,或者至少证明声明为纯的子集?或者这又是一件不必要的事情,因为程序员、

我最近读了很多关于函数式语言的文章,以及它作为一种纯函数式语言所带来的好处。(我对讨论Lisp的monad不感兴趣)尽可能(至少在逻辑上)隔离具有副作用的函数对我来说是有意义的。我已经使用了大量的
setf
和其他破坏性函数,并且我认识到在Lisp及其(大多数)派生语言中需要它们

我们开始:

  • (declare pure)
    这样的东西是否有助于优化编译器?或者这是一个没有实际意义的观点,因为它已经知道了
  • 声明是否有助于证明函数或程序,或者至少证明声明为纯的子集?或者这又是一件不必要的事情,因为程序员、编译器和验证程序已经明白了这一点
  • 如果没有其他原因,那么编译器是否有助于提高具有此声明的函数的纯度,并增加Lisp程序的可读性/可维护性
  • 这些有什么意义吗?还是我现在累得连想都不敢想
  • 如果您能在这里有任何见解,我将不胜感激。欢迎提供有关编译器实现或可证明性的信息

    编辑


    为了澄清,我不打算把这个问题限制在CommonLisp上。它显然(我认为)不适用于某些派生语言,但我也很好奇其他Lisp的某些功能是否倾向于支持(或不支持)这种功能。

    给定一个Lisp函数,知道它是纯函数还是非纯函数通常是不可判定的。当然,必要条件和充分条件可以在编译时测试。(如果根本没有不纯操作,则函数必须是纯的;如果无条件执行不纯操作,则函数必须是不纯的;对于更复杂的情况,编译器可以尝试证明函数是纯的或不纯的,但它不会在所有情况下都成功。)

  • 如果用户可以手动将函数注释为纯函数,那么编译器可以(a)更努力地证明函数是纯函数,即在放弃之前花费更多时间,或者(b)假设函数是纯函数,并添加对不纯函数不正确的优化(例如,记忆结果)。因此,是的,如果假设注释是正确的,那么将函数注释为纯函数可以帮助编译器

  • 除了上面的“更加努力”的启发法之外,注释将无助于证明东西,因为它不会向验证者提供任何信息。(换句话说,证明者可以假设注释在尝试之前总是存在的。)然而,将纯函数作为其纯度的证明是有意义的

  • 编译器可以(a.)检查纯函数在编译时是否确实是纯函数,但这通常是不可判定的,或者(b.)添加代码以尝试在运行时捕获纯函数中的副作用,并将其报告为错误。(a.)可能有助于使用简单的启发式方法(如“无条件执行不纯操作),(b.)有助于调试

  • 不,这似乎有道理。希望这个答案也有道理


  • 当我们可以假定纯粹性和参考性时,通常的好处适用 透明度。我们可以自动记忆热点。我们可以 自动并行计算。我们可以处理很多问题 竞争条件。我们也可以使用结构共享来共享我们需要的数据 know不能修改,例如(准)原语`cons() 不需要复制它考虑的列表中的cons单元格。 这些细胞不会受到另一个cons细胞的任何影响 这个例子有点明显,但编译器通常 在解决更复杂的结构共享方面表现出色

    然而,实际确定lambda(函数)是纯的还是有 引用透明性在Common Lisp中非常棘手。记住这一点 funcall(foo-bar)从查看(符号函数foo)开始 这个案子

    (defun foo (bar)
      (cons 'zot bar))
    
    foo()是纯的

    下一个lambda也是纯的

    (defun quux ()
     (mapcar #'foo '(zong ding flop)))
    
    但是,稍后我们可以重新定义foo:

    (let ((accu -1))
     (defun foo (bar)
       (incf accu)))
    
    对quux()的下一个调用不再是纯的!旧的纯foo()已被删除 重新定义为一个不纯的lambda.Yikes。这个例子可能有点 人为的,但从词汇上重新定义一些并不罕见 函数,例如一个let块。在这种情况下,它不是 可能知道编译时会发生什么

    Common Lisp具有非常动态的语义,因此 能够提前确定控制流和数据流(例如 编译时的实例)非常困难,而且在大多数情况下都非常有用 完全不可判定。这是具有动态 在Lisp中有很多你不能使用的常用习惯用法 如果你必须使用静态输入法,那么主要是这些输入法会影响你的输入 尝试做很多有意义的静态分析。我们可以为原语做 像犯人和朋友,但对于兰巴斯来说,除了 原始人我们身处更深的水域,尤其是在 我们需要看看函数之间复杂的相互作用,记住这一点 只有当它调用的所有lambda都是纯的时,lambda才是纯的

    (defun quux ()
     (mapcar #'foo '(zong ding flop)))
    
    在我的头顶上,有可能,通过一些深入的宏观研究, 从某种意义上说,每个lambda 一个额外的参数,它是一个表示整个状态的单子 lisp图像(我们显然可以限制自己使用什么函数 但能做到这一点可能更有用 声明我们自己的纯洁性,从我们向编译器承诺的意义上说 这个lambda确实是纯洁的,如果不是,后果就是
    没有定义,各种混乱可能接踵而至……

    你有两个答案,但都没有触及真正的问题

    首先,是的,知道一个函数是纯函数显然是好的