好吧,这个一直在唠叨我。鉴于实例种类繁多,让我们全力以赴,摆脱源类型和目标类型之间的任何关系,而不是实例的存在:
{-# LANGUAGE OverlappingInstances, FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses #-}
class Foo a b where f :: a -> b
现在我们可以将类型对与f
它们之间的类型进行匹配,但是我们喜欢,例如:
instance Foo Int Int where f = (+1)
instance Foo Int Integer where f = toInteger.((7::Int) -)
instance Foo Integer Int where f = fromInteger.(^ (2::Integer))
instance Foo Integer Integer where f = (*100)
instance Foo Char Char where f = id
instance Foo Char String where f = (:[]) -- requires TypeSynonymInstances
instance (Foo a b,Functor f) => Foo (f a) (f b) where f = fmap f -- requires FlexibleInstances
instance Foo Float Int where f = round
instance Foo Integer Char where f n = head $ show n
这确实意味着要避免大量显式类型注释No instance for...
和Ambiguous type
错误消息。例如,你不能做main = print (f 6)
,但你可以做main = print (f (6::Int)::Int)
您可以使用所需的标准类型列出所有实例,这可能会导致大量重复,您可以点亮蓝色触摸纸并执行以下操作:
instance Integral i => Foo Double i where f = round -- requires FlexibleInstances
instance Real r => Foo Integer r where f = fromInteger -- requires FlexibleInstances
注意:这并不意味着“嘿,如果你有一个整数类型,你可以使用这个方便的圆形函数免费i
拥有一个实例”,它的意思是:“每次你有任何类型,它肯定是一个实例
。通过方式,我正在使用这个,所以除非你的类型是,否则我们会失败。” 例如,对于该实例来说,这是一个大问题。Foo Double i
i
Foo Double i
round
i
Integral
Foo Integer Char
这很容易破坏你的其他实例,所以如果你现在输入f (5::Integer) :: Integer
你会得到
Overlapping instances for Foo Integer Integer
arising from a use of `f'
Matching instances:
instance Foo Integer Integer
instance Real r => Foo Integer r
您可以更改您的编译指示以包含 OverlappingInstances:
{-# LANGUAGE OverlappingInstances, FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses #-}
所以现在f (5::Integer) :: Integer
返回 500,很明显它使用的是更具体的Foo Integer Integer
实例。
我认为这种方法可能对您有用,手动定义许多实例,仔细考虑何时完全疯狂地从标准类型类中创建实例。(或者,标准类型并不多,众所周知,notMany choose 2 = notIntractablyMany
,因此您可以将它们全部列出。)