让我们考虑一个具有许多构造函数的数据类型:
data T = Alpha Int | Beta Int | Gamma Int Int | Delta Int
我想编写一个函数来检查是否使用相同的构造函数生成两个值:
sameK (Alpha _) (Alpha _) = True
sameK (Beta _) (Beta _) = True
sameK (Gamma _ _) (Gamma _ _) = True
sameK _ _ = False
维护sameK
没什么乐趣,不能轻易检查其正确性。例如,当新的构造函数添加到T
,很容易忘记更新sameK
。我省略了一行来举个例子:
-- it’s easy to forget:
-- sameK (Delta _) (Delta _) = True
问题是如何避免样板代码sameK
?或者如何确保它检查所有T
构造函数?
我发现的解决方法是为每个构造函数使用单独的数据类型,派生Data.Typeable
,并声明一个通用类型类,但我不喜欢这个解决方案,因为它的可读性要差得多,否则只有一个简单的代数类型适合我:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Typeable
class Tlike t where
value :: t -> t
value = id
data Alpha = Alpha Int deriving Typeable
data Beta = Beta Int deriving Typeable
data Gamma = Gamma Int Int deriving Typeable
data Delta = Delta Int deriving Typeable
instance Tlike Alpha
instance Tlike Beta
instance Tlike Gamma
instance Tlike Delta
sameK :: (Tlike t, Typeable t, Tlike t', Typeable t') => t -> t' -> Bool
sameK a b = typeOf a == typeOf b
另一种可能的方式:
sameK x y = f x == f y
where f (Alpha _) = 0
f (Beta _) = 1
f (Gamma _ _) = 2
-- runtime error when Delta value encountered
运行时错误并不理想,但比默默给出错误答案要好。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)