AI中的Lisp:自修改代码和特定于域的抽象级别

时间:2016-04-05 03:18:48

标签: lisp artificial-intelligence

AI以各种不同的语言实现,例如Python,C / C ++,Java,所以有人可以向我解释使用Lisp如何让人们执行#5(Peter Norvig在这里提到):< / p>

  
      
  1. [Lisp允许...]一个宏系统,让开发人员创建特定于域的级别   构建下一个级别的抽象。 ......今天,(5)是   只有Lisp擅长的功能与其他功能相比   语言。
  2.   

来源:https://www.quora.com/Is-it-true-that-Lisp-is-highly-used-programming-language-in-AI

我基本上对创建特定于域的抽象级别意味着什么感到困惑。有人可以提供一个具体的例子/应用程序,了解它何时/如何有用,一般来说,这意味着什么?我试过阅读http://lambda-the-ultimate.org/node/4765,但并没有真正“全面了解”。但是,我觉得这里有一些魔力,因为Lisp允许你编写其他程序/ OOP /函数语言不会让你的代码。然后我发现了这篇文章:https://www.quora.com/Which-programming-language-is-better-for-artificial-intelligence-C-or-C++,其中最顶层的回答是:

  

对于通用人工智能,我不会选择和   LISP的计划。真正的AI会有很多自我修改的代码   (你不认为一个真正的AI会把它的程序员所写的东西当作The   最后一句话,不是吗?)。

这让我更感兴趣,这让我想知道:

AI对于具有“自我检查,自我修改的代码”(来源:Why is Lisp used for AI?)以及为什么/如何有用这一点到底意味着什么?这听起来很酷(就好像人工智能对自己的操作有自我意识,可以这么说),听起来好像使用Lisp可以让人完成这些事情,而其他语言甚至都不会想到它(对不起,如果天真地快乐,我绝对没有Lisp的经验,但我很高兴开始)。我读了一下:What are the uses of self modifying code?并立即对特定AI应用程序的前景以及自修改代码的未来前沿感兴趣。

无论如何,我绝对可以看到能够编写自修改代码,并且能够在特定研究问题域上定制语言之间的联系(我认为Peter Norvig在他的帖子中暗示了这一点) ,但我真的很不确定这是什么意思,我想了解上面提到的这两个方面(“特定领域的抽象层次”)的细节(甚至只是本质)。和“自我检查,自我修改的代码”)以清晰的方式。

1 个答案:

答案 0 :(得分:6)

  

[Lisp允许...]一个宏系统,它允许开发人员创建特定于域的抽象级别,以构建下一级别。 ......今天,(5)是Lisp与其他语言相比擅长的唯一功能。

对于Stack Overflow来说,这可能过于宽泛,但是域特定抽象的概念是在许多语言中发生的,它在Common Lisp中只是更容易。例如,在C中,当您调用 open()时,会返回文件描述符。它是一个小整数,但是如果你坚持使用域模型,你不在乎它是一个整数,你关心它是一个文件描述符,并且在它的位置使用它是有意义的打算使用文件描述符。不过,它是leaky abstraction,因为这些调用往往通过返回负整数来发出错误信号,所以实际上必须关心文件描述符的事实是一个整数,因此您可以可靠地比较结果并确定它是否是错误。在C中,您可以定义将一些信息捆绑在一起的结构或记录类型。这提供了稍高的抽象量。

抽象的概念是,你可以考虑如何使用某些东西,它代表什么,并根据领域而不是代表性来思考。所有编程语言在某种意义上都支持这一点,但Common Lisp使得构建看起来就像语言内置的语言结构变得更加容易,并且有助于避免冗余(并且容易出错)样板。

例如,如果您正在编写natural deduction style定理证明器,则需要定义一组推理规则并使其可用作证明系统。其中一些规则将更加简单,并且不需要了解当前的证明范围。例如,检查是否使用连词消除(来自A∧B,推断 A (或 B ) ))是合法的,你只需要检查前提和结论的形式。没有抽象,你可能必须写:

(defun check-conjunction-elimination (premises conclusion context)
   (declare (ignore context))
   (and (= (length premises) 1)
        (typep (first premises) 'conjunction)
        (member conclusion (conjunction-conjuncts (first premises))
                :test 'proposition=)))

(register-inference-rule "conjunction elimination" 'check-conjunction-elimination)

通过定义抽象的能力,您可以编写一个模式匹配器,可以将其简化为:

(defun check-conjunction-elimination (premises conclusion context)
   (declare (ignore context))
   (proposition-case (premises conclusion)
     (((and A B) A) t)
     (((and A B) B) t)))

(register-inference-rule "conjunction elimination" 'check-conjunction-elimination)

(当然,有些语言内置了模式匹配(Haskell,Prolog(在某种意义上)),但重点是模式匹配是一个过程过程,你可以用任何语言实现它。但是,它是一个< em>代码生成进程,在大多数语言中,你必须在编译期间将代码生成作为单独的传递。使用Common Lisp,它是语言的一部分。)

您可以将该模式抽象为:

(define-simple-inference-rule "conjunction elimination" (premises conclusion)
  ((and A B) A)
  ((and A B) B)))

你仍然会生成原始代码。这种抽象节省了很多的空间,这意味着当其他人进来时,他们不需要知道所有的Common Lisp,他们只需要知道如何使用限定-简单推理规则即可。 (当然,这会添加一些开销,因为它是需要知道如何使用的其他东西。)但是这个想法仍然存在:代码对应于你谈论域的方式,而不是编程语言的工作方式。

对于“自我修改代码”,我认为这个术语比你实际上看到的好用途还要多。在上面描述的宏扩展意义上,有一种自修改代码(因为宏扩展代码知道如何“修改”或将代码转换成其他东西,但我不认为这是一个很好的例子)。由于您可以访问 eval ,因此您可以将代码修改为对象并对其进行评估,但我认为很多人并不真正提倡这样做。能够动态地重新定义代码可能很方便,但是我认为你会看到人们在REPL中比在程序中做得更多。

然而,能够返回闭包(越来越多的语言支持的东西)是一个很大的帮助。例如,trace是“某种”自我修改。你可以实现这样的东西:

(defmacro trace (name)
  (let ((f (symbol-function name)))
    (setf (symbol-function name)
          (lambda (&rest args)
            (print (list* name args))
            (apply f args)))))

你需要做更多的事情来支持 untrace ,但我认为这一点非常明确;您可以在运行时以可预测的方式执行更改函数行为等的操作。 跟踪和日志工具是一个简单的示例,但如果系统决定分析它知道的一些重要的方法,它可以动态地决定开始缓存一些结果,或者做其他有趣的事情。这是一种非常有用的“自我修改”。