假设我有以下代码
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
Asnot
没有在IsTall
s 上定义,只有Bool
s。
我可以一直明确地提取Bool
s ,但这在很大程度上违背了目的。
基本上,我希望IsTall
s 与其他IsTall
s 交互,就像它们是Bool
s 一样,只是它们不会在没有显式强制转换的情况下与Bool
s 和s 交互。IsAlive
实现这一目标的最佳方法是什么。
ps 我想我已经通过在 GHC 中的数字实现了这一点:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype UserID = UserID Int deriving (Eq, Ord, Num)
newtype GroupID = GroupID Int deriving (Eq, Ord, Num)
(即 UserID 和 GroupID 不应该交互)
但我似乎无法用Bool
s 做到这一点(派生 Bool 不起作用)。我什至不确定以上是最好的方法。