假设我有一个函数原型如下:
func :: [Int] -> [Int]
如何仅将非负的整数列表强制实施为输入参数?我必须将[Int]的param类型改为什么..?在这个公平的时刻,它与func [-1,-2]一起工作,我只希望它与[1,2]一起使用,即解释器喷出错误信息。
答案 0 :(得分:7)
newtype NonNegative a = NonNegative a
toNonNegative :: (Num a, Ord a) => a -> NonNegative a
toNonNegative x
| x < 0 = error "Only non-negative values are allowed."
| otherwise = NonNegative x
fromNonNegative :: NonNegative a -> a
fromNonNegative (NonNegative x) = x
请注意不要直接使用NonNegative构造函数。如果将其放在单独的模块中并且不导出它,这将更容易。
此外,现在您可以使用(map toNonNegative)来懒惰地转换数字列表。
无论您在哪里注入原始数字,都仍需要运行时检查。
或者,您可以使用Data.Word。
答案 1 :(得分:4)
答案 2 :(得分:1)
您可以使用Peano numbers,将您的函数类型更改为[Peano] -> ...
。但是,无论何时调用函数,都必须将转换函数从整数添加到peano数字并返回。
或者您可以添加运行时检查:
func xs
| any (< 0) xs = error "only non-negative integers allowed as input"
| otherwise = ...
请注意,后一种解决方案会使您的函数strict。
答案 3 :(得分:1)
smart constructors上的维基页面可能会给你一些想法。
答案 4 :(得分:0)
在GHC 7.10.1及更高版本中包含版本&gt; = 4.8.0.0的基本软件包中,现在有一个Natural类型可以满足您的需求 - 您只需将代码更改为:
import Numeric.Natural (Natural)
func :: [Natural] -> [Int]
然而,它更接近Integer
而不是Int
,因为与Integer
类似,与Int
不同,它没有最大值。
因为Natural
与Integer
一样,是Num
和Integral
的一个实例,所有相同的算术运算和转换函数都可用{{1} }}。尝试计算负Integer
将在运行时抛出Natural
,这是Underflow
。此外,方便的是,您可以仅使用整数文字创建ArithException
,而无需转换:
Natural
但是,如果您希望保留固定大小的整数域,那么也有一个解决方案 - 它已经存在了很长时间 - GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help
Prelude> :m +Numeric.Natural
Prelude Numeric.Natural> 2 :: Natural
2
来自the module Data.Word(对于8位非负整数,它还包含例如Word
。您可以像Word8
一样使用Word
。但是,请注意 - Natural
类型将以静默方式下溢,而不会抛出异常:
Word