我正在学习Haskell,并希望在一些构造函数中强制使用正整数(1,2,3,...),但我似乎只能找到' Int'和'整数'数据类型。
我可以使用规范
data Nat = Zero | Succ Nat
然后我不能用1,4,......来表示它们。
所以我问,有没有办法实现这个目标? (就像在C中使用' unsigned')
提前致谢。
编辑: 我正在将其隐藏在模块中,正如C. A. McCann所解释的那样。另外,我必须添加以下链接:http://haskell.org/haskellwiki/Smart_constructors以获取有关该主题的摘要。感谢您抽出宝贵时间回答!
答案 0 :(得分:19)
通常有两种方法:您给出的归纳定义,或使用其他东西进行内部表示的抽象数据类型。
请注意,归纳表示对于大数字而言并不是非常有效;然而,它可以是懒惰的,这可以让你做一些事情,比如看看两个nat中哪一个更大而不进一步评估较小的那个。
抽象数据类型是在单独的模块中定义的,不导出其构造函数的类型,例如IO
或Data.Set.Set
。你可以定义这样的东西:
module Nat (Nat() {- etc. -} ) where
newtype Nat = Nat { unNat :: Integer }
...在Nat
上导出各种操作的地方,即使内部表示只是Integer
,也要确保没有{{1}类型的值构造时保持负值。
在这两种情况下,如果你想使用数字文字,你需要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
实例,因为它会愉快地打破你的非负面约束
答案 1 :(得分:9)
您可以使用Data.Word中的Word32,它对应于C中的uint32_t。
使用Word32,您会遇到与C中的无符号类型相同的问题,尤其是上溢和下溢。如果要确保不会发生这种情况,则需要将其包装为newtype并仅导出智能构造函数。因此,不可能有加法,减法等,并且不存在上溢或下溢的风险。例如,如果要支持添加,可以添加和导出用于添加无符号整数的函数,但检查溢出(并且会降低性能)。它可能看起来像这样:
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))
答案 2 :(得分:3)
我不记得它是否解决了你的具体问题,但你可能会喜欢Colin Runciman的论文What about the natural numbers?。如果你无法越过付费专区,似乎有version at Citeseer。