【问题标题】:How do I enforce run-time conditions on data in Haskell?如何对 Haskell 中的数据强制执行运行时条件?
【发布时间】:2018-12-10 23:51:06
【问题描述】:

我想定义一个函数f [Int] -> Int,其中f 等于列表中元素的总和,如果列表的长度是一个完美的正方形,否则是未定义的。在 Haskell 中执行此操作的惯用方式是什么?

在命令式语言中,我会在assert sqrt(len(xs)) is integer 的效果上添加一行,以便为未定义的情况生成异常。 在像 Haskell 这样的强类型函数式语言中,您希望在类型系统中构建未定义的条件,但是这里不能这样做,因为没有“长度完美平方列表”类型。

我宁愿让程序在未定义的情况下因错误而停止,而不是让函数返回Nothing

【问题讨论】:

  • 还要小心你如何进行实际测试。进行某种按位测试(例如 popcount n == 1 或其他东西)可能是最快且最明显正确的......我想谷歌它

标签: haskell functional-programming


【解决方案1】:

如果您想正式一点,这可能是一个使用smart constructor 的好机会。

module PSqList
    ( PSqList   -- constructor *not* exported
    , fromList
    )
where

newtype PSqList a = PSqList [a]
    deriving (Functor, Foldable)

fromList :: [a] -> Maybe (PSqList a)
fromList xs
    | isPerfectSquare (length xs) = Just (PSqList xs)
    | otherwise = Nothing

那么当你使用PSqList模块时,你只能构造一个具有完美正方形长度的PSqLists。

使用整个模块来做这样的事情感觉有点奇怪;也许你想要一个更通用的不变跟踪系统。这是一个像 Agda 这样的依赖类型语言的域,但在 Haskell 中有一个可爱的中点可用,如函数珍珠 Ghosts of Departed Proofs 所示。

【讨论】:

    【解决方案2】:

    我宁愿让程序在未定义的情况下因错误而停止,而不是让函数返回 Nothing。

    执行此操作的标准和惯用方式当然是返回 Maybe Int,而不是按照您说的去做。

    如果你问如何从纯代码中引发错误,你可以这样做

    f ... = error "oops it wasn't a perfect square"
    

    另一种可能是您输入的[Int] 类型不正确。也许您想要的是一个保证为两个长度的幂的列表。在这种情况下,您可以创建一个智能构造函数(该函数是生成PowerOfTwoList a 的唯一方法,并且会进行验证)。您还可以使用某种长度索引向量,其中类型级别 natural 是 2 的幂(即列表的长度在类型中表示,并且通过构造也是正确的)

    【讨论】:

      猜你喜欢
      • 2012-07-01
      • 2019-11-07
      • 2021-03-29
      • 1970-01-01
      • 2014-06-16
      • 1970-01-01
      • 2020-05-01
      • 2018-02-12
      • 1970-01-01
      相关资源
      最近更新 更多