【问题标题】:Is there a practical way of using natural numbers in Haskell?有没有在 Haskell 中使用自然数的实用方法?
【发布时间】:2011-10-16 14:05:30
【问题描述】:

我正在学习 Haskell,并希望在某些构造函数中强制使用正整数 (1,2,3, ...),但我似乎只找到了 'Int' 和 'Integer' 数据类型。

我可以使用规范的

data Nat = Zero | Succ Nat

但后来我不能用 1、4、... 来表示它们。

所以我问,有没有办法做到这一点? (这就像在 C 中使用 'unsigned')

提前致谢。

编辑:正如 C. A. McCann 所解释的那样,我将把它隐藏在一个模块中。另外,我必须添加以下链接:http://haskell.org/haskellwiki/Smart_constructors 以获取有关该主题的摘要。感谢您抽出宝贵时间回答!

【问题讨论】:

  • 我还是更喜欢你的方式。尽管您不能使用那种含糖的语法,但您仍然可以使用常规的旧函数来生成列表。

标签: haskell types integer unsigned


【解决方案1】:

通常有两种方法:您给出的归纳定义,或使用其他东西进行内部表示的抽象数据类型。

请注意,归纳表示对于大数并不是非常有效;但是,它可能是惰性的,它可以让您执行诸如查看两个 nat 中的哪一个更大,而无需进一步评估较小的那一个的大小。

抽象数据类型是在单独的模块中定义且不导出其构造函数的数据类型,例如IOData.Set.Set。你可以这样定义:

module Nat (Nat() {- etc. -} ) where

newtype Nat = Nat { unNat :: Integer }

...您在Nat 上导出各种操作,这样即使内部表示 只是Integer,您也可以确保不会构造任何Nat 类型的值来保存负值。

在这两种情况下,如果你想使用数字文字,你需要一个 fromInteger 的定义,它附加到 Num 类型类,这对于自然数来说是完全错误的,但是哦。

如果您不介意为了获得语法上的好处而创建一个损坏的实例,您可以执行以下操作:

instance Num Nat where
    Zero + n = n
    n + Zero = n
    (Succ n1) + (Succ n2) = Succ . Succ $ n1 + n2

    fromInteger 0 = Zero
    fromInteger i | i > 0 = Succ . fromInteger $ i - 1

...等等,对于其他功能。抽象数据类型方法也可以这样做,只是要小心不要使用deriving 来获得自动的Num 实例,因为它会很高兴地打破你的非负约束。 p>

【讨论】:

  • -1 映射到S Z 的fromInteger 实现不是更有用吗?
【解决方案2】:

你可以使用Data.Word中的Word32,对应C中的uint32_t。

使用 Word32,您会遇到与 C 中的无符号类型相同的问题,尤其是上溢和下溢。如果你想确保不会发生这种情况,你需要将它包装成一个新类型,并且只导出一个智能构造函数。因此,不可能进行加法、减法等操作,并且不存在上溢或下溢的风险。例如,如果您想支持加法,您可以添加和导出一个用于添加无符号整数的函数,但需要检查溢出(并且会降低性能)。它可能看起来像这样:

module NT(UInt, addUInts) where

import Data.Word

newtype UInt = UInt Word32
  deriving (Show)

mkUInt :: Word32 -> UInt
mkUInt = UInt

addUInts :: UInt -> UInt -> Maybe UInt
addUInts (UInt u1) (UInt u2) =
  let u64 :: Word64
      u64 = fromIntegral u1 + fromIntegral u2
  in if u64 > fromIntegral (maxBound :: Word32)
       then Nothing
       else Just (UInt (fromIntegral u64))

【讨论】:

  • 我不喜欢这样,但我猜没有其他选择是正确的吗?
【解决方案3】:

我不记得它是否解决了您的具体问题,但您可能喜欢 Colin Runciman 的论文 What about the natural numbers?。如果您无法通过付费墙,似乎有一个version at Citeseer

【讨论】:

    猜你喜欢
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    • 2014-01-03
    • 1970-01-01
    相关资源
    最近更新 更多