Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Haskell中有使用自然数的实用方法吗?_Haskell_Types_Integer_Unsigned - Fatal编程技术网

在Haskell中有使用自然数的实用方法吗?

在Haskell中有使用自然数的实用方法吗?,haskell,types,integer,unsigned,Haskell,Types,Integer,Unsigned,我正在学习Haskell,希望在一些构造函数中强制使用正整数(1,2,3,…),但我似乎只找到“Int”和“Integer”数据类型 我可以用经典的 data Nat = Zero | Succ Nat 但是我不能用1,4。。。表示它们 所以我问,有没有办法做到这一点?(这类似于在C中使用“unsigned”) 提前谢谢 编辑:正如C.a.McCann所解释的,我将把它隐藏在一个模块中。此外,我还必须添加以下链接:以获取有关该主题的摘要。感谢您抽出时间回答 您可以从中使用Word32,它对应于

我正在学习Haskell,希望在一些构造函数中强制使用正整数(1,2,3,…),但我似乎只找到“Int”和“Integer”数据类型

我可以用经典的

data Nat = Zero | Succ Nat
但是我不能用1,4。。。表示它们

所以我问,有没有办法做到这一点?(这类似于在C中使用“unsigned”)

提前谢谢

编辑:正如C.a.McCann所解释的,我将把它隐藏在一个模块中。此外,我还必须添加以下链接:以获取有关该主题的摘要。感谢您抽出时间回答

您可以从中使用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))
module Nat (Nat() {- etc. -} ) where

newtype Nat = Nat { unNat :: Integer }
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

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

请注意,归纳表示法对于大数不是非常有效;但是,它可能是懒惰的,这让您可以做一些事情,比如查看两个NAT中的哪一个更大,而无需进一步评估较小NAT的大小

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

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))
module Nat (Nat() {- etc. -} ) where

newtype Nat = Nat { unNat :: Integer }
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
…在这里,您可以导出对
Nat
的各种操作,这样,即使内部表示形式只是
Integer
,也可以确保构造的
Nat
类型的值中没有包含负值

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

如果您不介意创建一个断开的实例来获得语法细节,您可以这样做:

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))
module Nat (Nat() {- etc. -} ) where

newtype Nat = Nat { unNat :: Integer }
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

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

我不记得它是否解决了您的特定问题,但您可能会喜欢Colin Runciman的论文。如果你不能越过付费墙,那似乎有一个问题。

我还是喜欢你的方式。虽然你不能使用这种甜言蜜语的语法,但你仍然可以使用常规的旧函数来生成列表。我不喜欢这样,但是我猜没有其他选择了,对吗?映射
-1
sz
的fromInteger实现不是更有用吗?