簡體   English   中英

Haskell:對數據類型的算術運算

[英]Haskell: arithmetic operations on data types

我試圖了解數據類型,並且要這樣做,我想嘗試模擬整數值。 我用以下方式定義它:

data Number = Zero | One | Two | Three deriving (Eq,Ord,Show)

因此,基本上,我希望能夠使用這種類型的元素進行基本的算術運算。 類似於

addNumber :: Number -> Number -> Number

像addNumber一二這樣調用將得到三。 但是,我真的不確定如何正確執行此操作。 我認為可以通過相互比較Number來做到這一點,但是要從中得到任何東西,我需要能夠以這種特定順序訪問下一個Number,但是我沒有知道如何處理給定的數據類型。 到目前為止,我正在做這樣的事情:

getIntDex :: Number -> Int
getIntDex n = intDex n 0 nList

nList :: [Number]
nList = [Zero, One, Two, Three]

intDex :: Number -> Int -> [Number] -> Int
intDex e i (x:xs) = if((compare e x) == EQ)
            then i
            else intDex e (i+1) xs

至少將其“轉換”為整數,以便實際上可以對其進行算術運算。 但是,這感覺有點靜態,整體上是錯誤的(我可能可以通過開關,防護罩或類似的東西更快地完成此操作。是否有更好的方法?

我假設您希望避免使用內置算術-否則,因為您觀察到可以將其轉換為內置數字,執行算術並轉換回去,但是從“學習Haskell”的角度來看,這並不是很令人滿意。

在新數據類型上定義新功能的標准方法是使用模式匹配。 例如,一種簡單的解決方法是列出所有輸入對Number以及它們的總和:

add :: Number -> Number -> Number
add Zero  Zero  = Zero
add Zero  One   = One
add Zero  Two   = Two
add Zero  Three = Three
add One   Zero  = One
add One   One   = Two
-- ...

當然,從程序員的角度看,這看起來有些令人生畏,而且模棱兩可。 另一方面,拆分一些功能可能會減少這種情況; 例如,您可以編寫一個函數以添加一個函數並對其進行迭代:

addOne :: Number -> Number
addOne Zero  = One
addOne One   = Two
addOne Two   = Three
addOne Three = Zero

add :: Number -> Number -> Number
add Zero  = id
add One   = addOne
add Two   = addOne . addOne
add Three = addOne . addOne . addOne

當然,這會稍微降低效率。 並且您不想對較大的數字類型執行此操作。 但這需要更少的手指打字。 (無論如何,對於較大的數字類型,您可能想要的是不同於大枚舉的實現(例如,比特流),但是我認為這是重點。)

如果還派生一個Enum實例,則可以使用fromEnum :: Enum a => a -> Int toEnum :: Enum a => Int -> a fromEnum :: Enum a => a -> InttoEnum :: Enum a => Int -> a在數據類型和與它們在數據定義中位置相對應的整數之間進行轉換。 既然你有Zero在第0位置,等等,這將是正是你想要什么要和整數。

但是您還應該考慮: addNumber Three Two的結果是什么? 那里沒有正確的值,因為您對數字的定義不會達到5。 無論您設置了什么上限,您都將擁有一個“部分”函數,該函數在其域中的某些值上是未定義的。 如果您只是對數據類型進行練習,那么這可能對您來說很好,但是通常在Haskell程序中,我們會盡量避免使用部分函數,​​因為在“應該”在編譯時被捕獲的情況下,它們可能會導致運行時錯誤。 例如,您可以返回Maybe Number而不是Number ,如果沒有有效答案,則返回Nothing 然后,調用者可以顯式應對失敗的可能性,而不是隱式接受失敗並遭受異常。

您的電話號碼非常混亂。 這樣,如果您想直接定義加法(而不是通過標准類型Int並使用標准+的繞道而行),則必須這樣做:

addNumber Zero n = n -- Zero added to anything is n
addNumber One One = Two
addNumber One Two = Three
addNumber Two One = Three
addNumber _ _ = error "overflow, we only go up to Three"

詳盡列出每個案例(幸運的是,由於您最多只有Three ,所以數量並不多)。

您可以想象其他稍微多一些的結構編號,您可以在其中使用該結構更經濟地定義加法。 著名的例子是

data N = Z | S N

...“ Peano”數字的遞歸數據類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM