I am trying to define a function which would take a Double -> Double
function and return its mathematical derivative. I have tried doing the following:
der :: (Double -> Double) -> (Double -> Double)
der f
| f == exp = exp
| otherwise = undefined
but Haskell does not support ==
on Double -> Double
values. Is what I am trying to do impossible in Haskell?
We can also compare two numerical values to see which one is larger. Haskell provides a number of tests including: < (less than), > (greater than), <= (less than or equal to) and >= (greater than or equal to). These tests work comparably to == (equal to).
The == is an operator for comparing if two things are equal. It is quite normal haskell function with type "Eq a => a -> a -> Bool". The type tells that it works on every type of a value that implements Eq typeclass, so it is kind of overloaded.
My understanding is that, is not feasible always (my above example is feasible) for function types to be instances of the Eq class because they have to have the same number of arguments (two) and return the same type (Bool).
Ord is a subclass of Eq that is used for data types that have a total ordering (every value can be compared with another).
Yes, what you are trying to do is impossible in Haskell, and in general: deciding whether two functions are equal for all possible inputs (without just checking every input value, if that is even possible) is equivalent to solving the Halting problem.
However, in your specific case, you can get around it, using a custom type that simulates a Double
(i.e. has the same instances, and so can be used in place of it) but instead of evaluating to a number, it constructs an abstract representation of the operations the functions does. Expr
represents the right-hand side of a mathematical function definition 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
...
Then, using rank-2 types, you can define conversion functions that convert between functions that take any Floating
and Expr
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)
...
You can also define a function diff :: Expr -> Expr
that differentiates the expression:
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)
...
Having all these parts should mean that you can differentiate (some) functions, e.g.
f x = sin x + cos x * exp x
f' = toFunction . diff . fromFunction $ f
Caveats:
Eq
instance for Expr
is tricky (it is equivalent to the Halting problem, since it is basically asking if two functions are equal),It is in general impossible to test functions for equality, since function equality should be extensional, i.e., two functions are equal if they give the same results for all arguments.
But there are other ways to define derivatives in Haskell that uses different types. For example, Automatic Differentiation, simpler version of AD.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With