簡體   English   中英

高階函數haskell

[英]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”函數的第一個參數。 因此,我們只需要在xrec方面編寫這個函數,這很簡單:

\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 0acc將開始的。

如果你想了解更多關於折疊的信息,我建議你自己重新實現它們。

編寫類似內容的最簡單方法是讓編譯器指導您。

首先,只看一下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 = vowelsr = 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.

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