fac n = if n < 2 then 1 else n * fac (n-1)
main = do
putStrLn "Enter a number: "
number <- getLine
print $ number >>= fac
我不知道如何編寫沒有if語句的遞歸階乘函數。我們的教授說了一些關於lambda微積分的話。如何在haskell中編寫遞歸階乘函數而沒有if else語句
fac n = if n < 2 then 1 else n * fac (n-1)
main = do
putStrLn "Enter a number: "
number <- getLine
print $ number >>= fac
我不知道如何編寫沒有if語句的遞歸階乘函數。我們的教授說了一些關於lambda微積分的話。如何在haskell中編寫遞歸階乘函數而沒有if else語句
模式匹配和警衛是兩種特別直接的方式。警衛本質上是if-then-else的另一種語法;它們看起來像這樣:
fac n | n < 2 = 1
| otherwise = n * fac (n-1)
與if-then-else不同,它們乾淨地支持多種條件;例如,人們也可以編寫,例如,
fac n | n < 0 = error "nah"
| n == 0 = 1
| n == 1 = 1
| n > 1 = n * fac (n-1)
這在if-then-else形式中看起來會少得多。
隨着模式匹配,一個通常寫入多個定義方程:
fac 0 = 1
fac 1 = 1
fac n = n * fac (n-1)
特別是對於數字,這也desugars基本上一個if-then-else的;但對於編譯器集成較少的數據類型,通常不能用if-then-else來模擬,而且通常也會導致非常自然的代碼。
另一個非常不錯的方法是將您的遞歸推送到現有的Prelude函數中;您在實踐中發現迭代模式的次數越多,您可以通過不重複實施相同的循環來避免更多的錯誤。對於這一個,你可以使用product
和特殊語法枚舉:
fac n = product [1..n]
更先進的(和顯著惡化)技術是定義一個新的號碼;例如教會數字允許數字的生產者驅動遞歸,消費者(這裏,fac
)只提供基本情況。在這種風格,你可能會看到這樣的事情:
fac n = fst (n (1,1) (\(prod, sum) -> (prod*sum, sum+1)))
(但注意哦,這需要一種非常特殊的號碼 - 肯定的fac
類型是不是可以接受的功能之一Int
或Integer
!)這個笑話在The Evolution of a Haskell Programmer被採取了它的邏輯和令人震驚的結論。
不要忘記'(==)'中的'Bool'上的模式匹配,這就是守衛和if/then/else都是糖的原因。(Haskell可能有太多特殊的方法來處理布爾) – Carl
如果/ then/else和守衛實際上只是模式匹配的語法糖。
if b
then c
else d
desugars到
case b of
True -> c
False -> d
同樣,
f x
| b = c
| d = e
f x = g
desugars到
f x = case b of
True -> c
False -> case d of
True -> e
False = g
所以,你總是可以直接使用case
。但是,您可以手動執行相當簡單的優化。如果你看到
case x == p of
True -> a
False -> b
其中p
由構造和文字,你可以用
case x of
p -> a
_ -> b
更換整個事情試試這個:
factorial 0 = 1
factorial n = n * factorial (n - 1)
使用尾遞歸:
factorial n = f n 1
f 0 acc = acc
f n acc = f (n-1) (acc*n)
main = print $ factorial 5
輸出:
120
https://en.wikibooks.org/wiki/Haskell/Pattern_matching – Ryan
[舌在臉頰答案](https://www.willamette.edu/~fruehr/haskell/ evolution.html) – gallais