#haskell #recursion
Вопрос:
Я пытаюсь написать функцию с использованием рекурсии eval :: Int -> Bool
, которая возвращает значение true, если задан список, в котором каждое нечетное число больше десяти. Например:
eval [] == True
eval [1] == False
eval [2] == True
eval [1, 11, 21] == False
eval [2, 12, 22] == True
eval [21, 11] == True
Для этого я должен использовать рекурсию, и у меня есть базовый код:
eval :: [Int] -> Bool
eval [] = True
eval (x:xs) | mod x 2/= 0 amp;amp; x > 10 = True
| otherwise = eval xs
Код выполняется, но он не работает для списков с нечетным числом больше 10 в качестве первого ввода, так как он принимает первое значение списка в качестве стандартного. Я думаю, что сначала сортировка списка в порядке возрастания, а затем выполнение рекурсии будет работать, правильно ли это, и если да, то как мне это реализовать?
Ответ №1:
Вы не должны возвращаться True
, если mod x 2 /= 0 amp;amp; x > 10
. На этом этапе нам все еще нужно искать остальные цифры.
Таким образом, мы можем рекурсировать на хвосте, только если элемент четный или элемент больше 10. Действительно, если элемент даже тогда достаточен для продолжения, если это не так, нам нужно подтвердить, что это число больше 10.
Таким eval
образом, функция, таким образом, работает с:
eval :: [Int] -> Bool
eval [] = True
eval (x:xs) | even x || x > 10 = eval xs
| otherwise = False
Мы можем упростить это с помощью:
eval :: [Int] -> Bool
eval [] = True
eval (x:xs) = (even x || x > 10) amp;amp; eval xs
Мы также можем реализовать функции без использования рекурсии, например, с foldr
помощью шаблона:
eval :: (Foldable f, Integral a) => f a -> Bool
eval = foldr (x -> ((even x || x > 10) amp;amp;)) True
или работать с all :: Foldable f => (a -> Bool) -> f a -> Bool
:
eval :: (Foldable f, Integral a) => f a -> Bool
eval = all (x -> even x || x > 10)
Комментарии:
1. @idontknowhowtocode: потому
foldr ... False
что создает функцию, и эта функция принимает список в качестве аргумента.2. @idontknowhowtocode: шаблон foldr заменяет каждый
:
из списка в функции (здесьx -> (even x || x > 10) amp;amp; xs
и используетсяTrue
для случая пустого списка[]
.3. @idontknowhowtocode: смотрите learnyouahaskell.com/higher-order-functions#folds
4.
all
определенно самый ясный, но не соответствует требованию, чтобы OP писал свою собственную рекурсию.x -> even x || x > 10
можно написать(||) <$> even <*> (>10)
, илиliftA2 (||) even (>10)
если вы в таком настроении.5. @dfeuer: Я согласен с тем, что
foldr
иany
не используют явную рекурсию, это было больше для того, чтобы показать, как использовать Haskell без необходимости определять рекурсивные функции.
Ответ №2:
Вы можете в значительной степени просто записать спецификацию проблемы:
f :: [Int] -> Bool
f = all (> 10) . filter odd
-- (And because you are supposed to write your own recursion)
where all p (x : xs) = p x amp;amp; all p xs
all p [] = True