使用Haskell的类型来替换断言语句或检查其他语言

Jas*_*sta 13 testing haskell types type-systems

对不起,如果问题非常简单,我对Haskell仍然很新.假设我有一个函数只能使用黄金比率中的两个数字(1.618),我如何定义myfun x y的类型以仅采用黄金比率数字.如果我在我的程序中调用没有黄金比例数字的myfun会出现什么情况(编译错误?)?如果没有黄金比例号码的呼叫是在运行时通过用户输入进行的,会发生什么?

Tho*_*son 18

您可能想要一个只能使用黄金比率数字构建的ADT,然后编写myfun以接受该数据类型.

我假设Integer是一个基类型,但你可以使用其他类型(例如:Double或Float)甚至是多态的.

1)进行ADT

module Golden (Gold, getGold, buildGold) where

data Gold = G Integer Integer

getGold :: Gold -> (Integer, Integer)
getGold (G x y) = (x, y)

buildGold :: Integer -> Integer -> Maybe Gold
buildGold x y
    | isGolden x y = Just (G x y)
    | otherwise    = Nothing
Run Code Online (Sandbox Code Playgroud)

请注意,此模块导出Gold类型但不导出构造函数(即不导出G).因此,获取类型值的唯一方法GoldbuildGold执行运行时检查 - 但只执行一次 - 因此可以使用Gold的值,并假设所有使用者都没有检查,这是黄金比率.

2)使用ADT构建 myfun

myfun :: Gold -> ???
myfun g = expr
  where (x, y) = getGold g
Run Code Online (Sandbox Code Playgroud)

现在,如果您尝试myfun使用非黄金数字(不是类型的值Gold)调用,那么您将收到编译时错误.

回顾要构建黄金数字buildGold必须使用函数,这会强制检查数字.

注意什么时候检查!您有一个编译时保证myfun,以及您要使用的所有其他功能Gold,始终提供黄金比率.程序输入(来自用户,网络或任何地方)仍然需要运行时检查,这就是buildGold提供的内容; 显然,永远不会有一个程序可以保证人类不会输入不受欢迎的东西.

您对问题的评论中给出的替代方案也值得考虑.如果你需要的只是一个单一的功能,那么ADT的重量会稍微大一些myfun,那么就会失败myfun :: (Integer, Integer) -> Maybe ???.

  • 保罗:我知道两个整数不会是一个黄金比例,也不会有任何n位数(例如:Double或Float).这就是为什么你没有`a/b == golden`而是需要某种近似相等或布尔测试,我称之为'isGolden'. (4认同)
  • 如果你想使用固定类型,`data Gold = G Double Double`; 你永远不会找到两个满足黄金比例的'整数'. (2认同)
  • 是的,我已经导出了那些 - 编辑过的.`Gold`是在没有构造函数的情况下导出的,所以除非你想要一个不必要的显式`()`,否则我不确定你想要什么.Kenny:显然这不会运行,因为省略的功能让提问者一起填写myfun,而不是实际存在于模块中或导入任何内容.ADT的概念非常重要. (2认同)

Don*_*art 10

最简单的技术是使用智能构造函数,它使用Int到GoldenInt的函数,检查您的值是否符合要求的比率.

通过更多努力,您可以使用类型级别编号来确保不需要运行时检查,但是,如果您是初学者,我会坚持使用智能构造函数方法.

汤姆上面的回答是这个成语的一个例子.