代码之家  ›  专栏  ›  技术社区  ›  Jason Christa

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

  •  13
  • Jason Christa  · 技术社区  · 14 年前

    抱歉,如果问题很简单,我对哈斯克尔还是很陌生的。假设我有一个函数,它只能处理黄金分割(1.618)中的两个数字,那么如何定义这些数字的类型呢 我的乐趣 x和y

    3 回复  |  直到 13 年前
        1
  •  18
  •   Thomas M. DuBuisson    14 年前

    你可能需要一个 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
    

    Gold G 黄金 buildGold

    2) 使用ADT构建 myfun

    myfun :: Gold -> ???
    myfun g = expr
      where (x, y) = getGold g
    

    如果你想打电话 我的乐趣 黄金 )然后您将得到一个编译时错误。

    扼要重述 建立黄金数字 建筑黄金 必须使用函数,这将强制检查数字。

    注意什么时候检查!你有一个编译时间保证 我的乐趣 ,以及要与一起使用的所有其他函数 黄金 ,总是提供黄金比例。程序输入(来自用户、网络或任何地方)仍然需要运行时检查,这就是原因 提供;显然,永远不会有一个程序能保证人类不会输入不需要的东西。

    对你问题的评论中给出的备选方案也值得考虑。如果你只需要一个单一的功能,ADT就有点重了, 我的乐趣 ,那可能会失败,然后就有了 myfun :: (Integer, Integer) -> Maybe ??? .

        2
  •  10
  •   Don Stewart    14 年前

    smart constructors ,它使用从Int到GoldenInt的函数来检查值是否在所需的比率中。

    再努力一点,你就可以 type level numbers 但是,为了确保不需要运行时检查,如果您是初学者,我将坚持使用智能构造函数方法。

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

        3
  •  1
  •   kennytm    12 年前

    你可以用 an assert ,这是您要替换的,

    checker :: a -> b -> Bool
    checker x y = x * 1.618 `approxEqual` y
    
    unsafeMyfun :: a -> b -> c
    unsafeMyfun x y = assert (checker x y) (doRealThingWith a b)
    

    或返回 Maybe a Either err a )为了避免在纯函数中捕捉不到的异常,

    myfun :: a -> b -> Maybe c
    myfun x y = do
                  guard $ checker x y
                  return $ doRealThingWith x y
    

    或者使用自定义的合同类型,如Tom的答案等。无论如何,都不可能检查约束 在编译时 . 事实上,由于IO monad,任何编译时约束都不可能精确。