Я пытаюсь реализовать полиморфную функцию, которая по существу пересекает тип, накапливая значение Tag
.Я бы хотел, чтобы пользователи могли делать, например, rec ((1,2), ('a', 3))
.
{-# LANGUAGE KindSignatures, PolyKinds, FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.Proxy
newtype Tag (a :: k) = Tag Int
deriving (Eq, Read, Show)
-- My users only have to define their own instances of this class...
class Tagged (a :: k) where
tag :: Tag a
-- ...like these:
instance Tagged Int where
tag = Tag 1
instance Tagged Char where
tag = Tag 2
instance Tagged (,) where
tag = Tag 3
-- While this is a morally "closed" class; implementing recursion over
-- components of types. This is what I'm struggling with:
class Rec (a :: k) where
rec :: proxy a -> Tag a
instance (Rec ab, Rec c)=> Rec (ab c) where
rec _ = let Tag ab = rec Proxy :: Tag ab
Tag c = rec Proxy :: Tag c
in Tag (ab * c)
instance {-# OVERLAPPABLE #-} Tagged a=> Rec a where
rec _ = tag :: Tag a
. Я возился с этим по-разному, и в текущем воплощении получаю ошибку (как для ab
, так и для c
, в первом случае):
• Could not deduce (Tagged ab) arising from a use of ‘rec’
from the context: (Rec ab, Rec c)
bound by the instance declaration at flook.hs:26:10-37
• In the expression: rec Proxy :: Tag ab
In a pattern binding: Tag ab = rec Proxy :: Tag ab
In the expression:
let
Tag ab = rec Proxy :: Tag ab
Tag c = rec Proxy :: Tag c
in Tag (ab * c)
|
27 | rec _ = let Tag ab = rec Proxy :: Tag ab
| ^^^^^^^^^
Я немного удивлен этой ошибкой, поскольку она, похоже, указывает на то, что второй базовый случай был выбран априори в теле первого экземпляра.
Есть ли способ заставить это работать или лучший подход?