2010-01-15 176 views
8

說我有一個函數原型如下:非負整數

func :: [Int] -> [Int] 

怎麼可能強制執行整數作爲輸入參數的唯一一個非負的名單?我將不得不將參數類型從[Int]更改爲..?在這個合適的時刻,它可以與func [-1,-2]一起工作,我只希望它能與[1,2]一起工作,即解釋器噴出錯誤信息。

回答

4
+0

我希望有人會顯示如何使用類型做到這一點,但現在我可以看到,這是不可能的 - 從評論非負的NonNegative.C類:「這個類的實例必須確保非負值,我們不能通過類型強制實現,但類型類NonNegative.C避免意外使用允許負數的類型。」多麼令人失望:-) – liwp 2010-01-15 13:44:22

1

您可以使用Peano numbers,將您的功能類型更改爲[Peano] -> ...。但是,當你調用你的函數時,你將不得不將整數轉換函數添加到peano數字中。

或者你可以添加一個運行時檢查:

func xs 
    | any (< 0) xs = error "only non-negative integers allowed as input" 
    | otherwise  = ... 

注意,後一種解決方案,使你的函數strict

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。

0

在基地包版本> = 4.8.0.0,它包含在GHC 7.10.1以上,現在還有一種類型Natural這你想要做什麼 - 你可以改變你的代碼:

import Numeric.Natural (Natural) 

func :: [Natural] -> [Int] 

然而,它接近於Integer而不是Int,因爲像IntegerInt不同,它沒有最大值。

因爲Natural,像Integer,是NumIntegral一個實例,所有相同的算術運算和轉換功能可作爲你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