Я пытаюсь создать аа системы, чтобы получить символические функции, и у меня есть проблема:Создание класса типов, который возвращает другой экземпляр этого класса типов в Haskell
У меня есть класс типов для выражений, Exp
, который определяет производная функция:
class Exp e where
derivative :: (Exp d) => e -> d
Я хочу, чтобы этот класс, чтобы иметь несколько экземпляров:
data Operator a b = a :* b | a :+ b
instance (Exp a, Exp b) => Exp (Operator a b) where
derivative (f :* g) = ((derivative f) :* g) :+ (f :* (derivative g)) --The derivative of the multiplication of two expressions
derivative (f :+ g) = derivative f :+ derivative g --The derivative of the addition of two expressions
instance Exp Double where
derivative a = (0 :: Double) --The derivative of a constant value is 0
instance Exp Char where
derivative c = (1 :: Double) --The derivative of just a variable is one
что я получаю я компилирую с GHCI является:
math.hs:19:21: error:
• Couldn't match expected type ‘d’ with actual type ‘Double’
‘d’ is a rigid type variable bound by
the type signature for:
derivative :: forall d. Exp d => Double -> d
at math.hs:19:5
• In the expression: (0 :: Double)
In an equation for ‘derivative’: derivative a = (0 :: Double)
In the instance declaration for ‘Exp Double’
• Relevant bindings include
derivative :: Double -> d (bound at math.hs:19:5)
math.hs:22:21: error:
• Couldn't match expected type ‘d’ with actual type ‘Double’
‘d’ is a rigid type variable bound by
the type signature for:
derivative :: forall d. Exp d => Char -> d
at math.hs:22:5
• In the expression: (1 :: Double)
In an equation for ‘derivative’: derivative c = (1 :: Double)
In the instance declaration for ‘Exp Char’
• Relevant bindings include
derivative :: Char -> d (bound at math.hs:22:5)
math.hs:28:27: error:
• Couldn't match expected type ‘d’
with actual type ‘Operator (Operator a0 b) (Operator a b0)’
‘d’ is a rigid type variable bound by
the type signature for:
derivative :: forall d. Exp d => Operator a b -> d
at math.hs:27:5
• In the expression: derivative f :+ derivative g
In an equation for ‘derivative’:
derivative (f :+ g) = derivative f :+ derivative g
In the instance declaration for ‘Exp (Operator a b)’
• Relevant bindings include
g :: b (bound at math.hs:28:22)
f :: a (bound at math.hs:28:17)
derivative :: Operator a b -> d (bound at math.hs:27:5)
Мой вопрос в том, почему проблемы моего экземпляра проблематичны? Производная в каждом всегда разрешается в экземпляр Exp
, который требуется типом constrain derivative
, поэтому почему он не может соответствовать типу?
Первая очевидная проблема заключается в том, что у вас есть тип переменной 'd' вместо' 'Double' в производной :: (Exp г) => e -> d'. – Alec
Я рекомендую вам не использовать класс типа здесь - у него нет никакой цели. Вместо этого сделайте себе тип данных 'Exp':' data Exp = Number Double | Variable Char | Exp: * Exp | Exp: + Exp', а затем определите 'производный :: Char -> Exp -> Exp', где первый аргумент - это переменная, по отношению к которой вы получаете. – Alec
Проблема в том, что вы хотите вернуть _some_ тип 'd', но ваша декларация объявляет' производную' возвращает _any_ 'd', независимо от того, что может выбрать _caller_. Таким образом, вы использовали универсальную количественную оценку вместо экзистенциальной квантификации. У Хаскелла нет экзистенциальности. Их можно определить, например. с пользовательским GADT, но они выглядят неправильно для этого - Alec above предлагает гораздо более простой вариант. – chi