7

我是 Haskell 新手,虽然之前有过 Lisp/Scheme 经验。现在我正在查看来自 SICP 的示例,并尝试在 Haskell 中实现它们以获得更多的实践经验。在第 3b 课中,作者提出了一个用于符号计算导数的函数。除其他外,它包含以下几行:

(define (deriv exp var)
    (cond ((constant? exp var) 0)
          ((same-var? exp var) 1)
; ...

在讲座中,定义了更多功能:

(define (constant? exp var)
    (and (atom? exp)
         (not (eq? exp var))))

有没有办法在 Haskell 中做同样的事情,即检查原子性和与其他函数的符号等价性?或者更一般地说,Haskell 中“反汇编”函数的方法是什么?

4

3 回答 3

6

首先,虽然 SICP 很棒,但我建议不要用它来学习 Haskell。(#) 这个问题的一些困难源于此。

在 Lisp/Scheme 中,“函数”被认为是一段代码,检查一个函数仅仅意味着检查它的代码。在 Haskell 中,“函数”意味着更接近其数学定义的东西,作为从集合 A 到集合 B 的映射。因此,例如,在 Lisp 上下文中,比较两个函数是有意义的:只需比较它们的代码。(但是是不同(x+y)^2x^2+2*x*y+y^2函数吗?)在 Haskell 中,这取决于是否存在确定您正在考虑的函数类的相等性的建设性程序。

同样,正如您的问题一样,在 Lisp/Scheme 中,您将编写一个“派生”函数,该函数在给定表达式时正确区分,并且只是错误输出或在任意输入上返回垃圾。在 Haskell 的类型系统下,这(AFAIK)是不可能的,因为——如果你想一想——没有区分任意输入这样的事情:你只能区分一个表达式(或者可能是一个更通用的类,但仍然不能一切)。所以在诺曼拉姆齐的回答中,你首先定义一个“表达式”类型(或类型类),这很简单,然后编写函数

derive :: Expression -> Expression

Expression它使用模式匹配结构(或其他取决于Expressions 的构建方式)来反汇编。


(#):原因是 SICP 有一个完全不同的理念,它涉及使用无类型的编程语言并鼓励缺乏代码和数据之间的区别。虽然“code=data”论证有一些优点(例如,在我们使用的 von Neumann 架构中,“一切都是 0 和 1”),但它不一定是推理或建模问题的好方法。(有关这方面的更多信息,请参阅 Philip Wadler 的Why Calculating is Better than Scheming。)如果您想阅读一本具有函数式风格而不是真实世界的 Haskell 书籍,也许是 Simon Thompson 的Haskell:函数式编程的工艺或 Richard Bird'

于 2009-02-14T07:53:03.600 回答
4

您的 Scheme 示例实际上并未检查 Scheme 函数。我最近在 Haskell 中对以下类型的值进行了一些符号区分:

data Exp a = Lit a
           | Exp a :*: Exp a
           | Exp a :+: Exp a
           | Var String
  deriving Eq

而不是使用atom?oreq?您使用case(或其他模式匹配)和==.

于 2009-02-13T23:55:49.720 回答
1

我不认为你能做到这一点。Lisp 是同音符号,Haskell 不是。

然而,进一步的谷歌搜索出现了Liskell,这是(?)一个有趣的混合体。

于 2009-02-13T22:29:36.370 回答