抱歉,我无法想象这个问题有更好的标题,所以请提前阅读。想象一下,我们有一个封闭类型的族,它将每种类型映射到它的相应Maybe
,除了maybes本身:
type family Family x where
Family (Maybe x) = Maybe x
Family x = Maybe x
我们甚至可以使用该类型族声明一个函数:
doMagic :: a -> Family a
doMagic = undefined
exampleA = doMagic $ Just ()
exampleB = doMagic $ ()
在GHCi中使用它表明可以评估此函数应用程序的类型:
*Strange> :t exampleA
exampleA :: Maybe ()
*Strange> :t exampleB
exampleB :: Maybe ()
问题是,除了doMagic
之外,是否可以提供undefined
函数的任何实现?比如说我想把每个值都包装成一个Just
构造函数,除了Maybes应该保持原样,我怎么能这样做呢?我尝试使用类型类,但如果不使用封闭类型系列,则无法为doMagic函数编写可编译签名,有人可以帮助我吗?
答案 0 :(得分:8)
您可以使用其他封闭类型系列来区分Maybe x
和x
,然后您可以使用另一个类型类为这两种情况提供doMagic
的单独实现。快速而肮脏的版本:
{-# LANGUAGE TypeFamilies, MultiParamTypeClasses,
FlexibleInstances, UndecidableInstances, ScopedTypeVariables #-}
type family Family x where
Family (Maybe x) = Maybe x
Family x = Maybe x
data True
data False
type family IsMaybe x where
IsMaybe (Maybe x) = True
IsMaybe x = False
class DoMagic a where
doMagic :: a -> Family a
instance (DoMagic' (IsMaybe a) a (Family a)) => DoMagic a where
doMagic = doMagic' (undefined :: IsMaybe a)
class DoMagic' i a r where
doMagic' :: i -> a -> r
instance DoMagic' True (Maybe a) (Maybe a) where
doMagic' _ = id
instance DoMagic' False a (Maybe a) where
doMagic' _ = Just
exampleA = doMagic $ Just ()
exampleB = doMagic $ ()
答案 1 :(得分:4)
你可以做出一个蹒跚而行的doMagic
函数。不幸的是,这个类型家庭的封闭对你来说并没有多大帮助。这是一个开始的样子
{-# LANGUAGE TypeFamilies #-}
type family Family x where
Family (Maybe x) = Maybe x
Family x = Maybe x
class Magical a where doMagic :: a -> Family a
instance Magical (Maybe a) where doMagic = id
instance Magical () where doMagic = Just
你可以看到它正如你所说的那样在ghci中工作:
*Main> doMagic $ Just ()
Just ()
*Main> doMagic $ ()
Just ()
那么为什么我说它一直在蹒跚而行呢?好吧,你可能已经注意到这两个提供的实例并不涵盖Haskell类型的大部分生态系统:
*Main> doMagic $ True
<interactive>:3:1:
No instance for (Magical Bool) arising from a use of ‘doMagic’
In the expression: doMagic
In the expression: doMagic $ True
In an equation for ‘it’: it = doMagic $ True
因此,必须为每个感兴趣的类型(构造函数)提供实例。事实上,即使是不连贯的实例 - 许多此类问题可以被提交的俱乐部 - 在这里也有帮助;如果有人试着写
instance Magical (Maybe a) where doMagic = id
instance Magical a where doMagic = Just
编译器正确地抱怨说,毕竟我们不知道完全多态的实例实际上是正确的类型。关于不连贯实例的事情是编译器告诉我们,只是因为那是选择的实例,其他实例肯定不适用。所以我们有可能在某个时候选择完全多态的实例,后来发现我们真的是幕后的Maybe
,然后我们只包了一层{{1}在事物周围。不幸的。
目前没有太多可以做的事情。目前封闭式家庭并不提供人们可能希望获得的所有知识。也许有一天,GHC将提供一种机制,使封闭式家庭在这方面更有用,例如类型不等式约束,但我不会屏住呼吸:如何提供这些有用的信息是一个研究问题,我没有听到任何有关人们处理它的谣言。