有一种方法,但它并不漂亮。我们将首先在类型类实例上创建我们希望看到的函数。
class IsOrd a where
isOrd :: a -> IO Bool
isOrd
最终会有两个实例,对应两个你case
的 s. 当然,简单的
instance Ord a => IsOrd a where
isOrd = putStrLn "Orderable!" >> return True
instance IsOrd a where
isOrd = putStrLn "Not orderable" >> return False
不起作用,因为实例头(IsOrd
)是相同的,编译器的工作方式是无论约束是否成立,它都匹配实例头,然后才检查约束。
现在是复杂的部分:这里和这里都有描述。(第二个链接,Oleg Kiselyov 关于类型类的集合,可能还有其他相关的东西,我不包括在这里,因为我还不知道。它也是一个很好的资源!)。它的本质是:
data HTrue
data HFalse
instance (Ord a) => IsOrd' HTrue a where
isOrd' _ x = putStrLn "Orderable." >> return True
instance IsOrd' HFalse a where
isOrd' _ x = putStrLn "Not orderable" >> return False
我们在实例头中添加了一个额外的类型级布尔值,以便您的示例中case
的 s 成为不同的实例头。很不错的主意!
您还必须担心其他细节,其中一些我不完全理解,但无论如何都很容易让它工作:这里有一些代码可以满足您的需求(您必须一直线程化 Eq 实例它,从IsOrd
开始,如果你也想要Eq
约束)。这是最终结果:
*Scratch> :l scratch.hs
[1 of 1] Compiling Scratch ( scratch.hs, interpreted )
Ok, modules loaded: Scratch.
*Scratch> isOrd (5::Int)
Orderable.
True
*Scratch> isOrd ('c')
Not orderable
False