我是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中“反汇编”函数的手段是什么?
答案 0 :(得分:6)
首先,虽然SICP很棒,但我会建议不要学习Haskell。(#)这个问题的一些难点源于此。
在Lisp / Scheme中,'function'被认为是一段代码,检查函数只是意味着检查它的代码。在Haskell中,'function'表示更接近其数学定义的东西,如从集合A到集合B的映射。例如,在Lisp上下文中,比较两个函数是有意义的:只需比较它们码。 (但是(x+y)^2
和x^2+2*x*y+y^2
是不同的函数吗?)在Haskell中,它取决于是否存在用于确定正在考虑的函数类的相等性的构造过程。
同样,在你的问题中,在Lisp / Scheme中,你会编写一个“derive”函数,在给定的表达式中正确区分,并且只输出错误或在任意输入上返回垃圾。在Haskell的类型系统下,这是(AFAIK)不可能做到的,因为 - 如果你想一想 - 没有区分任意输入的东西:你只能区分一个表达式(或者可能是一个更普通的类,但仍然没有一切)。因此,在Norman Ramsey的回答中,您首先定义一个“表达式”类型(或类型类),这很简单,然后编写函数
derive :: Expression -> Expression
使用模式匹配结构(或其他内容取决于Expression
的构建方式)反汇编Expression
。
(#):原因是SICP有一个完全不同的哲学,它涉及使用无类型编程语言并鼓励代码和数据之间缺乏区别。虽然“code = data”参数有一些优点(例如,在我们使用的von Neumann架构中,“无论如何都是0和1”),但它不一定是推理或建模问题的好方法。 (有关详细信息,请参阅Philip Wadler的Why Calculating is Better than Scheming。)如果您想阅读具有功能性而不是Real World的Haskell书籍,可能是Simon Thompson的Haskell: The Craft of Functional Programming或Richard Bird的{{ 3}}是更好的选择。
答案 1 :(得分:4)
您的Scheme示例实际上并未检查Scheme函数。我最近在Haskell中对以下类型的值进行了一些符号区分:
data Exp a = Lit a
| Exp a :*: Exp a
| Exp a :+: Exp a
| Var String
deriving Eq
您可以使用atom?
(或其他模式匹配)和eq?
,而不是使用case
或==
进行区分。
答案 2 :(得分:1)
我认为你不能那样做。 Lisp是homoiconic,Haskell不是。
然而,进一步的谷歌搜索出现了Liskell,这是(?)一个有趣的混合体。