Обратите внимание на эту программу:
class Convert a b where
convert :: a -> b
data A = A deriving Show
data B = B deriving Show
data C = C deriving Show
data D = DA A | DB B | DC C deriving Show
instance Convert A A where convert A = A
instance Convert A B where convert A = B
instance Convert A C where convert A = C
instance Convert B A where convert B = A
instance Convert B B where convert B = B
instance Convert B C where convert B = C
-- There is no way to convert from C to A
instance Convert C B where convert C = B
instance Convert C C where convert C = C
get (DA x) = convert x
get (DB x) = convert x
get (DC x) = convert x
main = do
print (get (DC C) :: B) -- Up to this line, code compiles fine.
print (get (DB B) :: A) -- Add this line and it doesn't, regardless of having a way to convert from B to A!
Существуют экземпляры для преобразования из C
в B
и от B
до A
. Тем не менее, GHC typechecks первый, но не подходит для последнего. При проверке кажется, что он не может вывести достаточно общий тип для get
:
get :: (Convert A b, Convert B b, Convert C b) => D -> b
Я хочу выразить: get:: (Convert a_contained_by_D b) = > D → b, что кажется невозможным. Есть ли способ реализовать и скомпилировать функцию, которая делает то, что делает мой get
, без изменения остальной части настройки?