我為一個非常簡單的實踐問題寫了一個解決方案:
我寫了一個解決方案。
考慮到每個方格上的麥粒數量是雙倍的,計算棋盤上的麥粒數量。寫出代碼,顯示給定方格上有多少麥粒,以及棋盤上麥粒的總數。
該函式必須回傳一個可能的整數,如果輸入小于1或大于64,則回傳無。
square :: Integer -> Maybe Integer :.
square n = if (n < 1| n > 64) then Nothing else Just (2^(pred n))
total :: Integer Integer
total = sum (fmap sum (map square [1...64] )
我試圖將fmap sum應用于GHCI中map square的一些測驗輸出(Maybe Integer的串列),并驚訝地發現它回傳整數的串列(不包括Just)而不是它們的總和。所以在上面的解決方案中,我第二次應用了sum來實際獲得總和。
我想從概念上理解為什么會出現這種情況:換句話說,為什么sum在這種情況下表現得像Maybe Ints到Ints的轉換器,而不是添加東西?
我已經解決了一些類似的練習,依靠輔助函式來避免對Maybe值進行計算的復雜性,也許在這種情況下,我應該只計算total的值而不利用square,即:
total = sum [2^n | n <- [0.63] ]
然而,由于我已經寫了一個有用的函式,我的第一直覺是重用它,這導致了一些未預見到的行為。
uj5u.com熱心網友回復:
讓我們看一下sum的型別:
sum :: (Foldable t, Num a) => t a -> a
通常,對于初學者來說,這可以通過假設t ~ []來簡化,所以我們使用sum作為
sum :: Num a => [a] -> a
如果我們在你的例子中試圖在這種型別下使用sum,我們會得到一個型別錯誤,因為你有一個Maybe數字的串列,而不是一個數字的串列。相反,你寫fmap sum [Just 1],將sum和fmap專業化為:
sum :: 可能 Integer -> Integer
fmap :: (Maybe Integer -> Integer) -> [Maybe Integer] -> [Integer]
所以問題并不是 "為什么sum沒有添加東西",而是 "當給定一個單一的Maybe Integer時,sum如何能有一個有意義的定義?"
如果你不熟悉如何將sum解釋為在Foldable上作業,或者Maybe是如何可折疊的,那么回答這個問題的一個方法就是嘗試自己實作它。實際上,只有一種合理的實作方式:
sum :: 可能 Integer -> Integer
sum Nothing = 0
sum (Just x) = x
對嗎?有人問你 "這里的數字的總和是多少",然后給你一個數字或零或一。很容易加起來。這正是sum對Maybe的作用,只不過它是通過Foldable而不是專門針對Maybe。
在這之后,當然很容易:你已經把你的[Maybe Integer]變成了一個[Integer],當然sum計算得到了非Nothing項的和。
uj5u.com熱心網友回復:
讓我們看一個例子。
map square [0. 2] = [Nothing, Just 1, Just 2]
fmap sum (map square [0. 2] = [sum Nothing。sum (Just 1), sum (Just 2) ]
由于Maybe是一個Foldable容器,計算其元素的總和是有意義的:
sum Nothing = 0
sum (Just a) = a
所以
fmap sum (map square [0. .2] = [0, 1, 2]
現在我不知道你實際上希望用Maybes做什么,但這就是你得到的原因。
uj5u.com熱心網友回復:
有一點值得內化;當你在一個串列上映射一個函式時1,其結果總是是一個具有相同數量元素的串列。該函式將被單獨應用于串列中的每個元素;它不能將它們合并為一個單一的摘要值。這不是fmap所要做的。
所以考慮到這個原則,我們知道fmap sum squares(其中squares = map square [1..64])不可能得到squares的總和。它將會是[ sum (square 1), sum (square 2), ... , sum (square 64) ]。如果我們想把它們加起來的話,我們將需要對整個串列再次應用sum。
這就留下了對sum (square 1)等實際上在做什么的解釋(也就是說,當應用于Maybe值時,sum做什么)。sum的正確型別是sum :: (Foldable t, Num a) => t a -> a。Foldable基本上是你可以按順序掃描0個或更多元素的結構的型別類(基本上是:那些你可以轉換為一個串列)。所有的sum都是將其中的元素相加,不管有多少元素(并使用0作為一個 "起始值",以防沒有元素)。Maybe有一個Foldable實體;它總是有0或1個元素,而sum可以把這些元素加起來,就像它可以把剛好只有0或1個元素的串列加起來一樣。
當然,零或一的數字相加的效果只是,如果有零的輸入,結果是0,如果有一的輸入,則等于輸入數字。 實際上從未被呼叫過這個 "和",這讓人感覺有點無意義。但是sum并不知道;它對任何Foldable都有效,不管它們包含多少元素。而Maybe也不知道它最終會被用于 "沒有實際加法的求和";它只是實作了Foldable,這樣任何想要從一個結構中掃描出可變數量元素的其他函式都可以掃描Maybes。
如果你認為這很傻,那就不要用sum來做這項作業;用fromMaybe 0來代替。
1 你可以把這一點推廣到串列以外的其他漏斗中;當你在一個資料結構上
fmap一個函式時,其結果將與輸入的結構完全相同。只有 "葉子節點 "是不同的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/316968.html
標籤:
