Самый простой способ написать что-то подобное - позволить компилятору вести вас.
Во-первых, взгляните только на очевидные части 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 (<b>x</b>:xs) = <b>if elem x "aeiou" then 1 + </b>vowels xs else vowels xs
Жирная часть по сути является функцией одного символа, которая дает модификатор числа.Таким образом, мы можем поместить это в реализацию 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