Вы просите создать список из непроходимого объекта без использования рекурсии, но я не думаю, что это действительно то, что вам нужно. В конце концов, любой обход будет использовать рекурсию — как вы думаете, как реализованы map
и foldl
? Я думаю, что более точный вопрос, который вы задаете, заключается в том, есть ли известная функция или встроенный способ выразить так называемую числовую складку, где рекурсия находится за кулисами, или неявная, а не явная, как в вашем примере foo
.
Что ж, один простой способ добиться этого — написать foldNum
функцию самостоятельно. Например:
foldNum :: Num n => (n -> a -> a) -> n -> a
foldNum f n = f n (foldNum f (n - 1))
Затем вы можете определить foo
как:
foo :: Integer -> [Integer]
foo = reverse . foldNum go . abs
where
go n a | n < 2 = []
| rem n 2 == 0 = n:a
| otherwise = a
Если вы немного разочарованы этим, я понимаю, почему: вы не очень много сэкономили, используя это определение foldNum
. На самом деле определение, которое я дал выше, даже не имеет встроенного базового варианта. Проблема сложения числа в том, что есть много способов сделать это! Вы можете вычесть или добавить любую сумму на каждом шаге, и нет четкого места для остановки (ноль может показаться естественным местом для остановки, но это верно только для неотрицательных чисел). Один из способов продолжить работу — попытаться сделать наш foldNum
еще более универсальным. Как насчет:
foldNum :: (n -> a -> a) -> (n -> Bool) -> (n -> n) -> a -> n -> a
foldNum f stop step a n
| stop n = a
| otherwise = foldNum f stop step (f n a) (step n)
Теперь мы можем записать foo
как:
foo :: Integer -> [Integer]
foo = foldNum (\x a -> if even x then x:a else a) (< 2) (subtract 1) [] . abs
Может быть, это то, что вы ищете?
Примечание: точно так же, как списки можно сворачивать влево или вправо (foldl
и foldr
), мы можем складывать числа двумя разными способами. Вы можете увидеть это, заменив последнюю строку приведенного выше определения foldNum
на::
| otherwise = f n $ foldNum f stop step a (step n)
Например, для foo
разница между ними заключается в порядке результирующего списка.
person
DDub
schedule
21.12.2020
foo
без использования рекурсии? Можете ли вы объяснить по-английски, что должна делать функцияfoo
? - person Aplet123   schedule 21.12.2020foldr
может генерировать потерянные для складных структур данных. Например, простой способ выполнитьtoList
для произвольной структуры данныхFoldable
— этоfoldr (:) []
. - person Willem Van Onsem   schedule 21.12.2020foo
. Будет обновлен вопрос, чтобы объяснить, что делает функция. - person category   schedule 21.12.2020\n fs -> [2,4..n] ++ fs
, но невозможно выполнить такое преобразование какой-либо общей функции, не зная, что эта функция делает. Для менее тривиальных функций может быть сложнее сделать их нерекурсивными. - person user2407038   schedule 21.12.2020