我试图定义一个函数,它将获取一个Double -> Double函数并返回其数学导数.我尝试过以下操作:
der :: (Double -> Double) -> (Double -> Double)
der f
| f == exp = exp
| otherwise = undefined
Run Code Online (Sandbox Code Playgroud)
但哈斯克尔不支持==的Double -> Double值.我在Haskell尝试做什么是不可能的?
huo*_*uon 24
是的,你所要做的是在Haskell不可能的,而且一般:确定两个函数是否对所有可能的输入相等(不只是检查每个输入值,如果这甚至有可能)等价于解决停机问题.
但是,在您的特定情况下,您可以使用模拟a的自定义类型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
...
Run Code Online (Sandbox Code Playgroud)
然后,您可以定义在函数和Floatings 之间进行转换的转换函数:
{-# 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)
...
Run Code Online (Sandbox Code Playgroud)
您还可以定义一个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)
...
Run Code Online (Sandbox Code Playgroud)
拥有所有这些部分应该意味着您可以区分(某些)功能,例如
f x = sin x + cos x * exp x
f' = toFunction . diff . fromFunction $ f
Run Code Online (Sandbox Code Playgroud)
注意事项:
diff :: Expr -> Expr实例Eq是棘手的(它相当于Halting问题,因为它基本上是在询问两个函数是否相等),