[英]higher order function haskell
我是Haskell的新手,我要做一個函數,使用高階函數foldr計算字符串中元音的數量
我試過創建這個功能
vowels [] = 0
vowels (x:xs)= if elem x "aeiou" then 1 + vowels xs else vowels xs
但它不起作用,我無法使用foldr
,任何建議嗎?
那么一個foldr :: (a -> b -> b) -> b -> [a] -> b
是一個函數,其中第一個參數是函數f :: a -> b -> b
。 您可以在此處將a
參數視為列表的“ head ”,將第二個參數b
視為使用foldr
遞歸的結果 ,因此您希望根據這兩個參數為整個函數生成結果。 該邏輯基本上封裝在函數的第二個子句中。
確實:
vowels (x:xs) = if elem x "aeiou" then 1 + vowels xs else vowels xs
可以改寫為:
vowels (x:xs) = if elem x "aeiou" then 1 + rec else rec
where rec = vowels xs
因此, rec
是遞歸調用的結果,是“fold”函數的第二個參數。 另一方面, x
是“fold”函數的第一個參數。 因此,我們只需要在x
和rec
方面編寫這個函數,這很簡單:
\x rec -> if elem x "aeiou" then 1 + rec else rec
此外,我們需要處理空列表的情況,這是您的函數的第一個子句。 在這種情況下,結果是0
,這是foldr
的第二個參數,所以我們得到:
vowels = foldr (\x rec -> if elem x "aeiou" then 1 + rec else rec) 0
或者更簡潔的語法:
vowels = foldr f 0
where f x rec | elem x "aeiou" = 1 + rec
| otherwise = rec
我們可以通過抽象rec
來進一步清理它:
vowels = foldr f 0
where f x | elem x "aeiou" = (1+)
| otherwise = id
你需要看看foldr
的簽名。
foldr :: Foldable t => (a -> b -> b) -> b -> ta -> b
別介意Foldable
部件,並專注於它所需的第一個功能。 (a -> b -> b)
b
與你應該返回的類型相同,所以直接將簽名轉換為lambda會給你\\x acc -> acc
,但你想做的不僅僅是忽略每個元素。
看看你的功能, if elem x "aeiou" then 1 + vowels xs else vowels xs
。 您需要返回b
,而不是遞歸添加一個。
if elem x "aeiou"
這部分很好。 then 1 + acc
< - 看看我在這做什么? 我正在向累加器添加一個,而不是手動遞歸,這是由foldr
完成的,就像else
情況一樣: acc
。 而已。 你甚至不需要觸摸x
。
把它們放在一起: vowels = foldr (\\x acc -> if elem x "aeiou" then 1 + acc else acc) 0
0
是acc
將開始的。
如果你想了解更多關於折疊的信息,我建議你自己重新實現它們。
編寫類似內容的最簡單方法是讓編譯器指導您。
首先,只看一下foldr
簽名的明顯部分。 這是傳統的簽名,專門用於列表。 現在, foldr
實際上可以在任何其他合適的容器上工作,但這在這里並不重要。
foldr :: (a -> b -> b) -- ^ Not obvious
-> b -- ^ Not obvious
-> [a] -- ^ A list... that'll be the input string
-> b -- ^ Final result, so nothing to be done here.
因此,您的實現將是形式
vowels :: String -> Int
vowels s = foldr _ _ s
我們還需要找出_
空檔中的內容。 編譯器將為您提供有用的提示:
$ ghc wtmpf-file6869.hs
[1 of 1] Compiling Main ( wtmpf-file6869.hs, wtmpf-file6869.o )
/tmp/wtmpf-file6869.hs:2:18: error:
• Found hole: _ :: Char -> Int -> Int
• In the first argument of ‘foldr’, namely ‘_’
In the expression: foldr _ _ s
In an equation for ‘Main.vowels’: Main.vowels s = foldr _ _ s
• Relevant bindings include
s :: String (bound at /tmp/wtmpf-file6869.hs:2:8)
vowels :: String -> Int (bound at /tmp/wtmpf-file6869.hs:2:1)
|
2 | vowels s = foldr _ _ s
| ^
所以,一個只占用一個字符的函數,然后修改一個整數。 這實際上已經是原始實現的一部分:
vowels (x:xs) = if elem x "aeiou" then 1 + vowels xs else vowels xs
粗體部分基本上是單個字符的函數,它產生數字修飾符。 所以我們可以使用lambda語法將它放在foldr
實現中:
vowels s = foldr (\x -> if x`elem`"aeiou" then (1+) else _) _ s
我必須將1+
放在括號中,以便它在沒有顯式參數的情況下工作,作為運算符部分 。
好的,差距更大:
• Found hole: _ :: Int -> Int
• In the expression: _
In the expression: if x `elem` "aeiou" then (1 +) else _
In the first argument of ‘foldr’, namely
‘(\ x -> if x `elem` "aeiou" then (1 +) else _)’
• Relevant bindings include
x :: Char (bound at wtmpf-file6869.hs:2:20)
s :: String (bound at wtmpf-file6869.hs:2:8)
vowels :: String -> Int (bound at wtmpf-file6869.hs:2:1)
|
2 | vowels s = foldr (\x -> if x`elem`"aeiou" then (1+) else _) _ s
| ^
這就是你找到非元音時應采取行動的修飾語。 在這種情況下你想要修改什么? 嗯,實際上沒有:計數應保持原樣。 這是由id
函數完成的。
vowels s = foldr (\x -> if x`elem`"aeiou" then (1+) else id) _ s
• Found hole: _ :: Int
• In the second argument of ‘foldr’, namely ‘_’
In the expression:
foldr (\ x -> if x `elem` "aeiou" then (1 +) else id) _ s
In an equation for ‘vowels’:
vowels s
= foldr (\ x -> if x `elem` "aeiou" then (1 +) else id) _ s
• Relevant bindings include
s :: String (bound at wtmpf-file6869.hs:2:8)
vowels :: String -> Int (bound at wtmpf-file6869.hs:2:1)
|
2 | vowels s = foldr (\x -> if x`elem`"aeiou" then (1+) else id) _ s
| ^
所以這是一個完全在foldr
之外的整數。 即它不能依賴於字符串。 特別是,如果字符串為空 ,也將使用它。 只能是0
!
vowels s = foldr (\x -> if x`elem`"aeiou" then (1+) else id) 0 s
沒有更多的差距,所以編譯器會接受這個。 測試一下:
$ ghci wtmpf-file6869
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
Loaded GHCi configuration from /home/sagemuej/.ghci
[1 of 1] Compiling Main ( wtmpf-file6869.hs, interpreted )
Ok, 1 module loaded.
*Main> vowels "uwkaefdohinurheoi"
9
您的定義可以調整為
vowels [] = 0
vowels (x:xs) = g x (vowels xs)
where
g x rec = if elem x "aeiou" then 1 + rec else rec
哪個匹配模式
foldr r z [] = z
foldr r z (x:xs) = r x (foldr r z xs)
如果我們有foldr rz = vowels
和r = g
,並且z = 0
。
該“模式”實際上是foldr
函數的有效定義。
因此我們確實有
vowels xs = foldr g 0 xs
where
g x rec = if elem x "aeiou" then 1 + rec else rec
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.