首先,虽然 SICP 很棒,但我建议不要用它来学习 Haskell。(#) 这个问题的一些困难源于此。
在 Lisp/Scheme 中,“函数”被认为是一段代码,检查一个函数仅仅意味着检查它的代码。在 Haskell 中,“函数”意味着更接近其数学定义的东西,作为从集合 A 到集合 B 的映射。因此,例如,在 Lisp 上下文中,比较两个函数是有意义的:只需比较它们的代码。(但是是不同(x+y)^2
的x^2+2*x*y+y^2
函数吗?)在 Haskell 中,这取决于是否存在确定您正在考虑的函数类的相等性的建设性程序。
同样,正如您的问题一样,在 Lisp/Scheme 中,您将编写一个“派生”函数,该函数在给定表达式时正确区分,并且只是错误输出或在任意输入上返回垃圾。在 Haskell 的类型系统下,这(AFAIK)是不可能的,因为——如果你想一想——没有区分任意输入这样的事情:你只能区分一个表达式(或者可能是一个更通用的类,但仍然不能一切)。所以在诺曼拉姆齐的回答中,你首先定义一个“表达式”类型(或类型类),这很简单,然后编写函数
derive :: Expression -> Expression
Expression
它使用模式匹配结构(或其他取决于Expression
s 的构建方式)来反汇编。
(#):原因是 SICP 有一个完全不同的理念,它涉及使用无类型的编程语言并鼓励缺乏代码和数据之间的区别。虽然“code=data”论证有一些优点(例如,在我们使用的 von Neumann 架构中,“一切都是 0 和 1”),但它不一定是推理或建模问题的好方法。(有关这方面的更多信息,请参阅 Philip Wadler 的Why Calculating is Better than Scheming。)如果您想阅读一本具有函数式风格而不是真实世界的 Haskell 书籍,也许是 Simon Thompson 的Haskell:函数式编程的工艺或 Richard Bird'