Ответ 1
Да, то, что вы пытаетесь сделать, невозможно в 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
...
Затем, используя типы ранга 2, вы можете определить функции преобразования, которые преобразуют между функциями, которые принимают любые Floating
и Expr
ы:
{-# 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
сложно (это эквивалентно проблеме Остановки, так как он в основном спрашивает, равны ли две функции), - Я на самом деле не проверял ни один из этого кода,
- дифференцирование и реконструкция выполняются во время выполнения, поэтому очень вероятно, что результирующая функция будет очень медленной.