Как проверить, все ли нечетные числа в списке больше 10

#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