2012-03-28 28 views
12

Próbuję zdefiniować funkcję, która miałaby funkcję Double -> Double i zwrócić jej pochodną matematyczną. Próbowałem w następujący sposób:Równość funkcji w Haskell

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

ale Haskell nie obsługuje == na Double -> Double wartości. Czy to, co próbuję zrobić w Haskellu, jest niemożliwe?

+0

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. –

Odpowiedz

20

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.
+2

Aby to było ogólne, potrzebujesz więcej niż jednego programu typu "X". I rzeczywiście, instancja 'Eq' _jest_ trudna. Kiedyś próbowałem, ale moja kontrola równości nie zakończyła się w przewidywalnym czasie z wyrażeń bardziej skomplikowanych niż np. '∂/∂x (a + x)/sin x'. – leftaroundabout

+1

W zależności od funkcji, które faktycznie dodajesz do typu danych Expr, może to być lub nie być równoznaczne z problemem zatrzymania. W niektórych przypadkach możesz normalizować swoje wyrażenia i sprawdzać, czy są one równoważne. Lub możesz stworzyć system przepisywania (który jest w pewnym sensie równoważny do zwykłych formularzy komputerowych), który może zdecydować, czy dwa wyrażenia są równe w ocenie z toFunkcja. – danr

11

Generalnie niemożliwe jest testowanie funkcji pod kątem równości, ponieważ równość funkcji powinna być ekstensjonalna, tj. Dwie funkcje są równe, jeśli dają takie same wyniki dla wszystkich argumentów.

Istnieją jednak inne sposoby definiowania pochodnych w Haskell, które używają różnych typów. Na przykład: Automatic Differentiation, simpler version of AD.

+0

+1 - ale szczegóły na temat innych sposobów definiowania instrumentów pochodnych byłyby miłe. –

+0

Nie interesuje mnie zróżnicowanie numeryczne. –

+5

To nie jest numeryczne zróżnicowanie, to bardzo różni się od tego. To nie jest ani numeryczne, ani symboliczne, ale trzecia tajemnicza alternatywa. :) – augustss