Хорошо, поэтому перед изменением, которое я хочу внести, я получил следующий упрощенный рабочий пример:
data D = D
data C = C
class T a where
t :: a
instance T D where
t = D
instance T C where
t = C
g :: T a => IO a
g = do
return t
main = (g :: IO D) >> return ()
Итак, проблема в том, что внутри g
мне нужны значения типов, не связанных a
быть выбранным на основе a
.Другими словами, я хочу выразить, что если a
равно C
, то будет выбрано какое-то значение еще не упомянутого типа e
, а если нет, то будет выбрано другое значение типа e
.Это в основном обусловливает произвольное равенство типов, например псевдокод if a ~ Bool then "foo" else "bar"
.Я попробовал это так (используя String
для типа e
в этом примере):
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
import Data.Proxy
class F sub1 sub2 where
f :: Proxy (sub1, sub2) -> String
instance {-# OVERLAPPABLE #-} F a b where
f _ = "did not match types"
instance {-# OVERLAPPING #-} F a a where
f _ = "matched types"
data D = D
data C = C
class T a where
t :: a
instance T D where
t = D
instance T C where
t = C
g :: forall a b. (T a, F b a) => IO a
g = do
putStrLn $ f (Proxy :: Proxy (D, a))
putStrLn $ f (Proxy :: Proxy (C, a))
return t
main = (g :: IO D) >> return ()
Я получаю следующие ошибки:
y.hs:30:14: error:
• Overlapping instances for F D a arising from a use of ‘f’
Matching instances:
instance [overlappable] F a b -- Defined at y.hs:10:31
instance [overlapping] F a a -- Defined at y.hs:13:30
(The choice depends on the instantiation of ‘a’
To pick the first instance above, use IncoherentInstances
when compiling the other instance declarations)
• In the second argument of ‘($)’, namely
‘f (Proxy :: Proxy (D, a))’
In a stmt of a 'do' block: putStrLn $ f (Proxy :: Proxy (D, a))
In the expression:
do putStrLn $ f (Proxy :: Proxy (D, a))
putStrLn $ f (Proxy :: Proxy (C, a))
return t
|
30 | putStrLn $ f (Proxy :: Proxy (D, a))
| ^^^^^^^^^^^^^^^^^^^^^^^^^
y.hs:31:14: error:
• Overlapping instances for F C a arising from a use of ‘f’
Matching instances:
instance [overlappable] F a b -- Defined at y.hs:10:31
instance [overlapping] F a a -- Defined at y.hs:13:30
(The choice depends on the instantiation of ‘a’
To pick the first instance above, use IncoherentInstances
when compiling the other instance declarations)
• In the second argument of ‘($)’, namely
‘f (Proxy :: Proxy (C, a))’
In a stmt of a 'do' block: putStrLn $ f (Proxy :: Proxy (C, a))
In the expression:
do putStrLn $ f (Proxy :: Proxy (D, a))
putStrLn $ f (Proxy :: Proxy (C, a))
return t
|
31 | putStrLn $ f (Proxy :: Proxy (C, a))
| ^^^^^^^^^^^^^^^^^^^^^^^^^
y.hs:34:9: error:
• Overlapping instances for F b0 D arising from a use of ‘g’
Matching instances:
instance [overlappable] F a b -- Defined at y.hs:10:31
instance [overlapping] F a a -- Defined at y.hs:13:30
(The choice depends on the instantiation of ‘b0’
To pick the first instance above, use IncoherentInstances
when compiling the other instance declarations)
• In the first argument of ‘(>>)’, namely ‘(g :: IO D)’
In the expression: (g :: IO D) >> return ()
In an equation for ‘main’: main = (g :: IO D) >> return ()
|
34 | main = (g :: IO D) >> return ()
| ^
Ошибки предполагаютIncoherentInstances
но не похоже, что он выбрал бы правильный экземпляр.Мне еще предстоит придумать что-то новое, чтобы попробовать.
РЕДАКТИРОВАТЬ: просто чтобы посмотреть, что произойдет, я активировал IncoherentInstances
, но это приводит к тем же ошибкам.
РЕДАКТИРОВАТЬ 2: Я объясню, как пример связан с моим практическим, реальным сценарием.g
представляет форму HTML.Эта форма может возвращать различные типы, представленные T
.Эти разные типы используют разные подмножества полей в форме.Строки в g
, которые имеют putStrLn
и f
, представляют определения полей в форме.f
представляет решение о том, проверять или нет поле в зависимости от того, возвращает ли форма тип, который зависит от него.
Например, форма может возвращать тип DocSectionA
или DocSectionB
.Поле может иметь тип Text
, и мы хотим выразить, что определенное поле должно проверяться только тогда, когда форма возвращает DocSectionA
, а другое поле должно проверяться только тогда, когда форма возвращает DocSectionB
.
Надеюсь, это поможет.