Tak, to, co próbujesz zrobić, jest niemożliwe w Haskell i ogólnie: decyzja, czy dwie funkcje są równe dla wszystkich możliwych danych wejściowych (bez sprawdzania każdej wartości wejściowej, jeśli jest to nawet możliwe) jest równoważna rozwiązaniu Problem zatrzymania.
Jednak w twoim konkretnym przypadku możesz obejść go, używając niestandardowego typu, który symuluje Double
(tzn. Ma te same instancje, i może być używany zamiast tego), ale zamiast oceniać na liczbę, konstruuje abstrakcyjną reprezentację operacji wykonywanych przez funkcje. Expr
reprezentuje prawą stronę definicji funkcji matematycznej 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
...
Następnie można zdefiniować funkcje konwersji, które przekształcają między funkcjami i Expr
s:
fromFunction :: Floating a => (a -> a) -> Expr
fromFunction f = f X
toFunction :: Expr -> (Double -> Double)
toFunction X = \x -> x
toFunction (Const a) = const a
toFunction (Plus a b) = \x -> (toFunction a x) + (toFunction b x)
...
Można również zdefiniować funkcję diff :: Expr -> Expr
że różnicuje wyrażenie:
diff X = Const 1
diff (Const _) = Const 0
diff (Plus a b) = Plus (diff a) (diff b)
diff (Exp a) = Mult (diff a) (Exp a)
...
posiadające wszystkie te części powinny oznaczać, że można rozróżnić (niektóre) funkcje, np
f x = sin x + cos x * exp x
f' = toFunction . diff . fromFunction $ f
Ostrzeżenia:
- to nie będzie działać w ogóle,
- definiowania kompletnego
Eq
instancję dla Expr
jest trudne (jest to równoznaczne z wstrzymaniem problemu, ponieważ jest w zasadzie pytanie, czy dwie funkcje są równe),
- Nie przetestowałem żadnego z tych kodów,
- the differentiati on i rekonstrukcja są wykonywane w czasie wykonywania, więc wynikowa funkcja z dużym prawdopodobieństwem będzie bardzo powolna.
Można to zrobić numerycznie za pomocą, 'f '(x) = (f (x + dx) - f (x))/dx' lub automatyczne różnicowanie. To, co próbujesz zrobić, jest niemożliwe w ogólnym przypadku dla języków Turinga-Complete. –