"模式匹配"的代数类型数据的构造
-
26-09-2019 - |
题
让我们来考虑一个数据类型与许多造:
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
解决方案
看看数据。数据模块, toConstr
功能尤其如此。随着 {-# LANGUAGE DeriveDataTypeable #-}
那会让你有1分行的解决方案,它适用于任何类型的实例 Data.Data
.你不需要找出所有的SYB!
如果由于某种原因(卡拥抱?), 这不是一个选项,然后这是一个非常丑陋的和非常缓慢的黑客。它只能如果你的数据类型是 Show
能(例如通过使用 deriving (Show)
-这意味着没有能种类内,实例)。
constrT :: T -> String
constrT = head . words . show
sameK x y = constrT x == constrT y
constrT
获取串表示的最外层构造的 T
值显示,砍成单词和随后得到的第一个。我得到一个明确的类型签名的所以你不想使用它在其他类型(与逃避monomorphism restriction).
一些显着的缺点:
- 这打破可怕的时候你的类型具有缀的构造(例如
data T2 = Eta Int | T2 :^: T2
) - 如果你的一些构造有一个共同的前缀,这是要获得较慢,作为一个较大部分的串具有可比性。
- 不会的工作类型与一个自定义
show
, 如许多图书馆的类型。
这就是说,它 是 Haskell98...但这是只有漂亮的事情,我可以说它!
其他提示
另一种可能的方式:
sameK x y = f x == f y
where f (Alpha _) = 0
f (Beta _) = 1
f (Gamma _ _) = 2
-- runtime error when Delta value encountered
一个运行时错误是不理想,但比默默地给错误的答案更好。
您需要使用一个泛型库像废你的样板或Uniplate中做到这一点一般。
如果你不想这么重的手,你可以用空记录的快捷方式使用戴夫韩丁的解决方案,一起:
...
where f (Alpha {}) = 0
f (Beta {}) = 1
f (Gamma {}) = 2
所以,你不必知道每个构造多少ARGS了。但它显然还剩下所需的东西。
在某些情况下,“废你的样板”库会有所帮助。
您绝对可以使用仿制药,以消除样板。你的代码是一个典型例子,为什么我(和许多其他的从不的使用在顶层_
通配符)。虽然这是繁琐的写出所有的情况下,它是比处理的错误少乏味。
在本实施例快乐我不会只使用戴夫辛顿的解决方案,但将涂上辅助功能f
一个INLINE附注