是否可以编写一个类型函数来接受像 Show 这样的约束并返回一个将 RHS 约束为不是Show 实例的类型?
签名将类似于
type family Invert (c :: * -> Constraint) :: * -> Constraint
是否可以编写一个类型函数来接受像 Show 这样的约束并返回一个将 RHS 约束为不是Show 实例的类型?
签名将类似于
type family Invert (c :: * -> Constraint) :: * -> Constraint
不,这是语言的设计原则,你永远不能这样做。规则是如果一个程序是有效的,添加更多instance
的 s 不应该破坏它。这是开放世界的假设。您想要的约束是一个非常直接的违规:
data A = A
f :: Invert Show a => a -> [a]
f x = [x]
test :: [A]
test = f A
会工作,但添加
instance Show A
会打破它。因此,最初的程序不应该是有效的,因此Invert
不可能存在。
正如 HTNW 回答的那样,通常不应该断言类型不是类的实例。然而,对于一个具体的类型,肯定有可能断言它永远不可能有某个类的实例。一种特别的方式是这样的:
{-# LANGUAGE ConstraintKinds, KindSignatures, AllowAmbiguousTypes
, MultiParamTypeClasses, FlexibleInstances #-}
import GHC.Exts (Constraint)
class Non (c :: * -> Constraint) (t :: *) where
nonAbsurd :: c t => r
但这是不安全的——编写实例的唯一方法是,例如,
instance Non Show (String->Bool) where
nonAbsurd = undefined
但是其他人可能会想出一个假的instance Show (String->Bool)
,然后就可以用你nonAbsurd
的来证明月亮是用绿色奶酪制成的。
使实例不可能的更好选择是“阻止”它:自己“先发制人”地编写该实例,但以这样一种方式实际调用它是一个类型错误。
import Data.Constraint.Trivial -- from trivial-constraint
instance Impossible0 => Show (String->Bool) where
show = nope
现在,如果有人尝试添加该实例或尝试使用它,他们将得到一个明确的编译器错误。