haskell - 相互引用的默认类型实例

标签 haskell typeclass type-families

有没有办法根据彼此定义默认类型实例?我试图让这样的工作:

{-# LANGUAGE DataKinds, KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
data Tag = A | B | C

class Foo (a :: *) where
    type Bar a (b :: Tag)

    type Bar a A = ()
    type Bar a B = Bar a A
    type Bar a C = Bar a A

instance Foo Int where
    type Bar Int A = Bool

test :: Bar Int B
test = True

但这不起作用:
Couldn't match type `Bar Int 'B' with `Bool'
In the expression: True
In an equation for `test': test = True

请注意,这也不起作用:
test :: Bar Int B
test = ()

最佳答案

是的,默认类型实例可以相互定义(从您自己的示例中可以看出):

instance Foo Int where
--    So the default recursive definition will be used instead
--    type Bar Int A = Bool

test :: Bar Int B
test = ()

但是,当您在实例定义中为 Int 重新定义关联类型同义词时你替换 整个 Bar 的默认 3 行定义(而不仅仅是 type Bar a A = () )只有一行 type Bar Int A = Bool这意味着 Bar Int BBar Int C不再定义。

所以我猜想按照您的意图使用递归默认值的一种方法是重新定义特定的同义词(尽管它相当冗长):
class Foo (a :: *) where
    type Bar a (b :: Tag)
    type Bar a A = BarA a
    type Bar a B = BarB a

    type BarA a
    type BarA a = ()

    type BarB a
    type BarB a = Bar a A

-- This now works
instance Foo Int where
    type BarA Int = Bool

test :: Bar Int B
test = True

可以回退到默认值:
-- As well as this one
instance Foo Int where
--    type BarA Int = Bool

test :: Bar Int B
test = ()

关于haskell - 相互引用的默认类型实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12199324/

相关文章:

scala - 在scala 2.13中,为什么有时无法显式调用类型类?

haskell - 一个类中的多个类型同义词

haskell - HList 与 DataKinds,种类不可提升

arrays - Haskell 中的稀疏数组?

haskell - 如何重置 Haskell 包缓存

scala - Haskell 如何区分不同的可能类型类实例

exception - 为什么Haskell中的()是Enum类型却没有实现succ函数

haskell - 为什么这个单射类型族实际上不是单射的?

haskell - GHC 重写规则是否知道识别语法糖?

haskell - 如何将上下文和 `IO` monad 隐藏到另一个 monad 中?