說我有一個函數原型如下:非負整數
func :: [Int] -> [Int]
怎麼可能強制執行整數作爲輸入參數的唯一一個非負的名單?我將不得不將參數類型從[Int]更改爲..?在這個合適的時刻,它可以與func [-1,-2]一起工作,我只希望它能與[1,2]一起工作,即解釋器噴出錯誤信息。
說我有一個函數原型如下:非負整數
func :: [Int] -> [Int]
怎麼可能強制執行整數作爲輸入參數的唯一一個非負的名單?我將不得不將參數類型從[Int]更改爲..?在這個合適的時刻,它可以與func [-1,-2]一起工作,我只希望它能與[1,2]一起工作,即解釋器噴出錯誤信息。
您可以使用Peano numbers,將您的功能類型更改爲[Peano] -> ...
。但是,當你調用你的函數時,你將不得不將整數轉換函數添加到peano數字中。
或者你可以添加一個運行時檢查:
func xs
| any (< 0) xs = error "only non-negative integers allowed as input"
| otherwise = ...
注意,後一種解決方案,使你的函數strict。
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。
smart constructors上的維基頁面可能會給你一些想法。
在基地包版本> = 4.8.0.0,它包含在GHC 7.10.1以上,現在還有一種類型Natural這你想要做什麼 - 你可以改變你的代碼:
import Numeric.Natural (Natural)
func :: [Natural] -> [Int]
然而,它接近於Integer
而不是Int
,因爲像Integer
和Int
不同,它沒有最大值。
因爲Natural
,像Integer
,是Num
和Integral
一個實例,所有相同的算術運算和轉換功能可作爲你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
但是,如果你寧願留在固定大小的整數的領域,對於一個解決方案, - 它已經存在了更長的時間 - Word
from the module Data.Word(它也包含例如用於8位非負整數的Word8
)。您將以與Natural
相同的方式使用Word
。然而,被警告 - 該Word
類型將悄無聲息下溢,沒有拋出異常:
GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help
Prelude> :m +Data.Word
Prelude Data.Word> 2 :: Word
2
Prelude Data.Word> it - 4
18446744073709551614
我希望有人會顯示如何使用類型做到這一點,但現在我可以看到,這是不可能的 - 從評論非負的NonNegative.C類:「這個類的實例必須確保非負值,我們不能通過類型強制實現,但類型類NonNegative.C避免意外使用允許負數的類型。」多麼令人失望:-) – liwp 2010-01-15 13:44:22