简体   繁体   English

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

[英]Is there a practical way of using natural numbers in Haskell?

I'm learning Haskell and would like to impose the use of positive integers (1,2,3, ...) in some constructors, but I only seem to find the 'Int' and 'Integer' datatypes. 我正在学习Haskell,并希望在一些构造函数中强制使用正整数(1,2,3,...),但我似乎只能找到'Int'和'Integer'数据类型。

I could use the canonical 我可以使用规范

data Nat = Zero | Succ Nat

but then I couldn't use 1, 4, ... to denote them. 但后来我不能用1,4,......来表示它们。

So I ask, is there a way to accomplish this? 所以我问,有没有办法实现这个目标? (which is like using 'unsigned' in C) (就像在C中使用'unsigned')

Thanks in advance. 提前致谢。

EDIT: I'm going the way of hiding it inside a module, as explained by CA McCann. 编辑:正如CA McCann所解释的那样,我将把它隐藏在一个模块中。 Also, I must add the following link: http://haskell.org/haskellwiki/Smart_constructors for a summary on the subject. 另外,我必须添加以下链接: http//haskell.org/haskellwiki/Smart_constructors以获取有关该主题的摘要。 Thanks for taking the time to answer! 感谢您抽出宝贵时间回答!

There's generally two approaches for this: The inductive definition you gave, or an abstract data type using something else for internal representation. 通常有两种方法:您给出的归纳定义,或者使用其他东西进行内部表示的抽象数据类型。

Note that the inductive representation is not terribly efficient for large numbers; 请注意,归纳表示对于大数字而言并不是非常有效; however, it can be lazy, which lets you do things like see which of two nats is larger without evaluating further than the size of the smaller one. 然而,它可以是懒惰的,这可以让你做一些事情,比如看看两个nat中哪一个更大,而不进一步评估较小的那个。

An abstract data type is one which is defined in a separate module and does not export its constructors, examples being IO or Data.Set.Set . 抽象数据类型是在单独的模块中定义的并且不导出其构造函数的类型,例如IOData.Set.Set You can define something like this: 你可以定义这样的东西:

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

newtype Nat = Nat { unNat :: Integer }

...where you export various operations on Nat such that, even though the internal representation is just Integer , you ensure that no value of type Nat is constructed holding a negative value. ...在Nat上导出各种操作,即使内部表示只是Integer ,也要确保没有构造Nat类型的值保持负值。

In both cases, if you want to use numeric literals, you'll need a definition of fromInteger , which is attached to the Num type class, which is completely wrong for natural numbers but oh well. 在这两种情况下,如果你想使用数字文字,你需要一个fromInteger的定义,它被附加到Num类型类,这对于自然数是完全错误的但是很好。

If you don't mind making a broken instance just to get syntactic niceties, you can do something like this: 如果你不介意制作一个破坏的实例只是为了获得语法细节,你可以这样做:

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

...and so on, for the other functions. ......等等,用于其他功能。 The same can be done for the abstract data type approach, just be careful to not use deriving to get an automatic Num instance , because it will happily break your non-negative constraint. 对于抽象数据类型方法也可以这样做,只是注意不要使用deriving来获取自动Num实例 ,因为它会愉快地打破你的非负约束。

You can use Word32 from Data.Word , which corresponds to uint32_t in C. 您可以使用Data.Word中的Word32 ,它对应于C中的uint32_t。

With Word32 you get the same problems as with the unsigned types in C, especially over- and underflow. 使用Word32,您会遇到与C中的无符号类型相同的问题,尤其是上溢和下溢。 If you want to make sure that doesn't happen, you'd need to wrap it to a newtype and only export a smart constructor. 如果要确保不会发生这种情况,则需要将其包装为newtype并仅导出智能构造函数。 Thus no addition, subtraction etc. would be possible and there's no risk of over- or underflow. 因此,不可能有加法,减法等,并且不存在上溢或下溢的风险。 If you wanted to support addition, for example, you could add and export a function for adding unsigned ints, but with a check for overflow (and with a performance penalty). 例如,如果要支持添加,可以添加和导出用于添加无符号整数的函数,但检查溢出(并且会降低性能)。 It could then look like this: 它可能看起来像这样:

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))

I can't remember whether it addresses your specific question, but you might like Colin Runciman's paper What about the natural numbers? 我不记得它是否解决了你的具体问题,但你可能会喜欢Colin Runciman的论文。自然数字怎么样? . In case you can't get over the paywall, there seems to be a version at Citeseer . 如果你无法克服付费墙, Citeseer似乎有一个版本

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM