AI 中的 Lisp:自修改代码和特定领域的抽象层次
Lisp in AI: self-modifying code and domain-specific levels of abstraction
AI 以多种不同的语言实现,例如 Python、C/C++、Java,所以有人可以向我解释一下使用 Lisp 究竟如何允许一个执行#5(Peter Norvig 在此处提到):
- [Lisp allows for..] A macro system that let developers create a domain-specific level of
abstraction in which to build the next level. ... today, (5) is the
only remaining feature in which Lisp excels compared to other
languages.
来源:https://www.quora.com/Is-it-true-that-Lisp-is-highly-used-programming-language-in-AI
我基本上对创建特定于域的抽象级别的含义感到困惑。有人可以提供 when/how 的具体 example/application 这会很有用吗?一般来说,这意味着什么?我尝试阅读 http://lambda-the-ultimate.org/node/4765 but didn't really "get the big picture." However, I felt like there is some sort of magic here, in that Lisp allows you to write the kind of code that other procedural/OOP/functional languages won't let you. Then I came across this post: https://www.quora.com/Which-programming-language-is-better-for-artificial-intelligence-C-or-C++,其中最热门的答案是:
For generic Artificial Intelligence, I would choose neither and
program in LISP. A real AI would have a lot of self-modifying code
(you don't think a real AI would take what its programmer wrote as The
Last Word, would you?).
这让我更加感兴趣,这让我想知道:
AI 拥有 "self-inspecting, self-modifying code" 究竟意味着什么(来源:Why is Lisp used for AI?) and, again, why/how this is useful? It sounds very cool (almost like as if the AI is self-conscious about its own operations, so to speak), and it sounds like using Lisp allows one to accomplish these kinds of things, where other languages wouldn't even dream of it (sorry if this comes off as naively jolly, I have absolutely no experience in Lisp, but am excited to get started). I read a little bit of: What are the uses of self modifying code?,并立即对特定 AI 应用的前景和自修改代码的未来前沿产生了兴趣。
无论如何,我绝对可以看出具有编写自修改代码的能力与能够在您的特定研究问题领域之上定制语言的能力之间的联系(我认为 Peter Norvig 在他的文章中暗示了这一点) post), 但我真的很不确定这到底是什么意思, 我想了解上面提出的这两个方面的基本要素 (甚至只是本质) ("domain-specific level of abstraction" 和 "self-inspecting, self-modifying code") 以一种清晰的方式。
[Lisp allows for..] A macro system that let developers create a domain-specific level of abstraction in which to build the next level. ... today, (5) is the only remaining feature in which Lisp excels compared to other languages.
这对于 Stack Overflow 来说可能过于宽泛,但是特定领域抽象的概念在很多语言中都存在,只是在 Common Lisp 中简单。例如,在 C 中,当您调用 open() 时,您会得到一个 文件描述符 。它是一个小整数,但如果你坚持域模型,你不关心它是一个整数,你关心它是一个 文件描述符 ,并且它有意义在需要 文件描述符 的地方使用它。不过,这是一个 leaky abstraction,因为这些调用倾向于通过 returning 负整数 来发出错误信号,所以你 do实际上必须关心文件描述符是一个整数这一事实,以便您可以可靠地比较结果并确定它是否是一个错误。在 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(某种意义上)),但关键是模式匹配是一个程序化的过程,你可以用任何语言实现它. 然而,这是一个代码生成过程,在大多数语言中,你必须在编译期间将代码生成作为一个单独的过程进行。对于 Common Lisp,它是语言的一部分。 )
您可以将该模式抽象为:
(define-simple-inference-rule "conjunction elimination" (premises conclusion)
((and A B) A)
((and A B) B)))
而且您仍然会生成原始代码。这种抽象节省了 space 的 lot,这意味着当其他人进来时,他们不需要知道所有的 Common Lisp,他们只需要知道如何使用 define-simple-inference-rule。 (当然,这会 add 一些开销,因为他们 do 需要知道如何使用它。)但想法仍然是那里:代码对应于您谈论域的方式,而不是编程语言的工作方式。
至于 "self modifying code",我认为这是一个您听到的术语多于您实际看到的良好用法。在上面描述的宏扩展的意义上,有一种自修改代码(因为宏扩展代码知道如何 "modify" 或将代码转换成其他东西,但我认为这不是一个很好的例子) .由于您有权访问 eval,因此您可以将代码作为对象进行修改并对其求值,但我认为并没有多少人真正提倡这样做。能够即时重新定义代码非常方便,但我认为您会再次看到人们在 REPL 中比在程序中做更多的事情。
然而,能够 return 闭包(越来越多的语言支持)是一个很大的帮助。例如,trace 是 "sort of" 自修改。你可以像这样实现它:
(defmacro trace (name)
(let ((f (symbol-function name)))
(setf (symbol-function name)
(lambda (&rest args)
(print (list* name args))
(apply f args)))))
您需要做更多的事情来支持 untrace,但我认为这一点很明确;您可以在 运行 时间以可预测的方式做一些改变函数等行为的事情。 trace 和日志工具是一个简单的例子,但是如果系统决定分析它知道重要的一些方法,它可以动态地决定开始缓存一些结果,或者做其他有趣的事情。这种 "self modification" 可能会很有帮助。
AI 以多种不同的语言实现,例如 Python、C/C++、Java,所以有人可以向我解释一下使用 Lisp 究竟如何允许一个执行#5(Peter Norvig 在此处提到):
- [Lisp allows for..] A macro system that let developers create a domain-specific level of abstraction in which to build the next level. ... today, (5) is the only remaining feature in which Lisp excels compared to other languages.
来源:https://www.quora.com/Is-it-true-that-Lisp-is-highly-used-programming-language-in-AI
我基本上对创建特定于域的抽象级别的含义感到困惑。有人可以提供 when/how 的具体 example/application 这会很有用吗?一般来说,这意味着什么?我尝试阅读 http://lambda-the-ultimate.org/node/4765 but didn't really "get the big picture." However, I felt like there is some sort of magic here, in that Lisp allows you to write the kind of code that other procedural/OOP/functional languages won't let you. Then I came across this post: https://www.quora.com/Which-programming-language-is-better-for-artificial-intelligence-C-or-C++,其中最热门的答案是:
For generic Artificial Intelligence, I would choose neither and program in LISP. A real AI would have a lot of self-modifying code (you don't think a real AI would take what its programmer wrote as The Last Word, would you?).
这让我更加感兴趣,这让我想知道:
AI 拥有 "self-inspecting, self-modifying code" 究竟意味着什么(来源:Why is Lisp used for AI?) and, again, why/how this is useful? It sounds very cool (almost like as if the AI is self-conscious about its own operations, so to speak), and it sounds like using Lisp allows one to accomplish these kinds of things, where other languages wouldn't even dream of it (sorry if this comes off as naively jolly, I have absolutely no experience in Lisp, but am excited to get started). I read a little bit of: What are the uses of self modifying code?,并立即对特定 AI 应用的前景和自修改代码的未来前沿产生了兴趣。
无论如何,我绝对可以看出具有编写自修改代码的能力与能够在您的特定研究问题领域之上定制语言的能力之间的联系(我认为 Peter Norvig 在他的文章中暗示了这一点) post), 但我真的很不确定这到底是什么意思, 我想了解上面提出的这两个方面的基本要素 (甚至只是本质) ("domain-specific level of abstraction" 和 "self-inspecting, self-modifying code") 以一种清晰的方式。
[Lisp allows for..] A macro system that let developers create a domain-specific level of abstraction in which to build the next level. ... today, (5) is the only remaining feature in which Lisp excels compared to other languages.
这对于 Stack Overflow 来说可能过于宽泛,但是特定领域抽象的概念在很多语言中都存在,只是在 Common Lisp 中简单。例如,在 C 中,当您调用 open() 时,您会得到一个 文件描述符 。它是一个小整数,但如果你坚持域模型,你不关心它是一个整数,你关心它是一个 文件描述符 ,并且它有意义在需要 文件描述符 的地方使用它。不过,这是一个 leaky abstraction,因为这些调用倾向于通过 returning 负整数 来发出错误信号,所以你 do实际上必须关心文件描述符是一个整数这一事实,以便您可以可靠地比较结果并确定它是否是一个错误。在 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(某种意义上)),但关键是模式匹配是一个程序化的过程,你可以用任何语言实现它. 然而,这是一个代码生成过程,在大多数语言中,你必须在编译期间将代码生成作为一个单独的过程进行。对于 Common Lisp,它是语言的一部分。 )
您可以将该模式抽象为:
(define-simple-inference-rule "conjunction elimination" (premises conclusion)
((and A B) A)
((and A B) B)))
而且您仍然会生成原始代码。这种抽象节省了 space 的 lot,这意味着当其他人进来时,他们不需要知道所有的 Common Lisp,他们只需要知道如何使用 define-simple-inference-rule。 (当然,这会 add 一些开销,因为他们 do 需要知道如何使用它。)但想法仍然是那里:代码对应于您谈论域的方式,而不是编程语言的工作方式。
至于 "self modifying code",我认为这是一个您听到的术语多于您实际看到的良好用法。在上面描述的宏扩展的意义上,有一种自修改代码(因为宏扩展代码知道如何 "modify" 或将代码转换成其他东西,但我认为这不是一个很好的例子) .由于您有权访问 eval,因此您可以将代码作为对象进行修改并对其求值,但我认为并没有多少人真正提倡这样做。能够即时重新定义代码非常方便,但我认为您会再次看到人们在 REPL 中比在程序中做更多的事情。
然而,能够 return 闭包(越来越多的语言支持)是一个很大的帮助。例如,trace 是 "sort of" 自修改。你可以像这样实现它:
(defmacro trace (name)
(let ((f (symbol-function name)))
(setf (symbol-function name)
(lambda (&rest args)
(print (list* name args))
(apply f args)))))
您需要做更多的事情来支持 untrace,但我认为这一点很明确;您可以在 运行 时间以可预测的方式做一些改变函数等行为的事情。 trace 和日志工具是一个简单的例子,但是如果系统决定分析它知道重要的一些方法,它可以动态地决定开始缓存一些结果,或者做其他有趣的事情。这种 "self modification" 可能会很有帮助。