【发布时间】:2012-05-19 16:10:26
【问题描述】:
假设我有以下代码
type IsTall = Bool
type IsAlive = Bool
is_short_alive_person is_tall is_alive = (not is_tall) && is_alive
稍后再说,我有以下内容
a :: IsAlive
a = False
b :: IsTall
b = True
并调用以下命令,以错误的方式获取两个参数:
is_short_alive_person a b
不幸的是,这成功编译,并且在运行时会找到高个子死人而不是矮个子人。
我希望上面的例子不要编译。
我的第一次尝试是:
newtype IsAlive = IsAlive Bool
newtype IsTall = IsTall Bool
但是我不能做类似的事情。
switch_height :: IsTall -> IsTall
switch_height h = not h
因为not没有在IsTalls上定义,只有Bools。
我可以一直明确地提取Bools,但这在很大程度上违背了目的。
基本上,我希望 IsTalls 与其他 IsTalls 互动,就像他们是 Bools 一样,除了他们不会在没有明确演员表的情况下与 Bools 和 IsAlives 互动.
实现这一目标的最佳方法是什么。
附言我想我已经通过在 GHC 中的数字实现了这一点:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype UserID = UserID Int deriving (Eq, Ord, Num)
newtype GroupID = GroupID Int deriving (Eq, Ord, Num)
(即 UserID 和 GroupID 不应交互)
但我似乎无法使用 Bools 执行此操作(导出 Bool 不起作用)。无论如何,我什至不确定以上是最好的方法。
【问题讨论】:
-
你想要的
IsTall和IsAlive类型是个糟糕的主意。这是对使用不相交类型来确保类型安全的通常不错的想法的错误概括。将此与您的UserID和GroupID进行比较;在这种情况下,拥有单独的类型是有意义的,因为在需要GroupID的地方传递UserId或将一个添加到另一个(尽管可能两者都不应该实现Num)是没有意义的。然而,测试一个人是高并且活着,高还是还活着,不高并且 活着,等等。 -
sacundim:在很大程度上,我改变了这个观点。我最终使用了
newtype Height = Tall | Short之类的东西,然后使用了x == Tall等。输入更多,但我认为它使代码更具可读性和类型安全性。
标签: haskell types casting type-safety