Haskell中函数的相等性

时间:2012-03-28 11:33:25

标签: haskell equality

我正在尝试定义一个函数,该函数将采用Double -> Double函数并返回其数学导数。我尝试过以下操作:

der :: (Double -> Double) -> (Double -> Double)
der f
    | f == exp = exp
    | otherwise = undefined

但Haskell不支持== Double -> Double值。我在Haskell中想做的事情是不可能的吗?

2 个答案:

答案 0 :(得分:23)

是的,你想要做的事情在Haskell中是不可能的,并且一般来说:决定两个函数对于所有可能的输入是否相等(不仅检查每个输入值,如果可能的话)等同于解决停止问题

但是,在您的特定情况下,您可以使用模拟Double的自定义类型(即具有相同的实例,因此可以代替它使用)来绕过它,而不是评估为一个数字,它构造函数所做操作的抽象表示。 Expr代表数学函数定义f(x) = ...的右侧。

data Expr = X | Const Double |
            Add Expr Expr | Mult Expr Expr |
            Negate Expr | Inverse Expr |
            Exp Expr | Log Expr | Sin Expr | ...
       deriving (Show, Eq)

instance Num Expr where
    (+) = Add
    (*) = Mult
    ...
instance Fractional Expr where
    recip = Inverse
    ...
instance Floating Expr where
    pi = Const pi
    exp = Exp
    log = Log
    sin = Sin
    ...

然后,使用rank-2 types,您可以定义转换函数,这些转换函数可以在采用任何FloatingExpr s的函数之间进行转换:

{-# LANGUAGE Rank2Types #-}

fromFunction :: (forall a. Floating a => (a -> a)) -> Expr
fromFunction f = f X

toFunction :: Expr -> (Double -> Double)
toFunction X = \x -> x
toFunction (Const a) = const a
toFunction (Add a b) = \x -> (toFunction a x) + (toFunction b x)
...

您还可以定义区分表达式的函数diff :: Expr -> Expr

diff X = Const 1
diff (Const _) = Const 0
diff (Add a b) = Add (diff a) (diff b)
diff (Exp a) = Mult (diff a) (Exp a)
...

拥有所有这些部分应该意味着你可以区分(某些)功能,例如

f x = sin x + cos x * exp x
f' = toFunction . diff . fromFunction $ f

<强>注意事项:

  • 这不会起作用,
  • Eq定义一个完整的Expr实例很棘手(它等同于Halting问题,因为它基本上是在询问两个函数是否相等),
  • 我实际上没有测试过任何代码,
  • 差异化和重建是在运行时完成的,因此产生的函数很可能非常慢。

答案 1 :(得分:11)

通常不可能测试函数是否相等,因为函数相等应该是扩展的,即如果它们为所有参数提供相同的结果,则两个函数是相等的。

但是还有其他方法可以在Haskell中定义使用不同类型的衍生物。例如,Automatic Differentiationsimpler version of AD