Ответ 1
Решение iterate
прекрасное, или вам может понравиться это: состав n
копий f
равен foldr (.) id (replicate n f)
.
Есть ли в Haskell библиотечная функция для создания функции с собой n раз?
Например, у меня есть эта функция:
func :: a -> a
и я хочу сделать это:
func . func . func . func . func . func , ...
(до n раз, где n известно только во время выполнения).
Обратите внимание, что функция итерации не подходит для того, что я делаю, так как мне не нужны промежуточные результаты.
Решение iterate
прекрасное, или вам может понравиться это: состав n
копий f
равен foldr (.) id (replicate n f)
.
\xs n -> iterate func xs !! n
(xs
- начальное значение, n
- сколько раз применить func
)
Я не знаю почему, но я чувствую, что iterate
- это то, что люди постоянно не изучают при изучении Хаскелла.
Если вам не нравится !!
, вы можете использовать zip
и lookup
в качестве альтернативы. (некоторым людям/группам/инструментам не нравятся функции, которые в некоторых случаях вызывают "ошибку", я не утверждаю, что поиск в этих случаях лучше)
lookup n . zip [0..] . iterate func
ОБНОВЛЕНИЕ: Хорошо, поэтому я удалил, а затем удалил, потому что я согласен с другим ответчиком - вы не должны сбрасывать со счетов использование итерации только потому, что оно дает вам больше, чем вам нужно.
Я не знаю, почему вы говорите, что iterate
не подходит. Он идеально подходит для этой цели. (!! n) . iterate func
является композицией n
копий func
.
(Кто-то отправил ответ, похожий на приведенный выше код, но он, похоже, удалил его.)
(\n -> appEndo . mconcat . replicate n . Endo) n f x
Я начинаю в Haskell, в настоящее время на пятой главе ( "Функции более высокого порядка" ) Учите вас в Haskell For Great Good! поэтому я еще не знаком с функциями, показанными в предыдущих ответах. Учитывая то, что я понимаю до сих пор, я бы сделал это следующим образом:
applyNTimes :: Int -> (a -> a) -> a -> a
applyNTimes n f x
| n == 0 = x
| otherwise = f (applyNTimes (n-1) f x)
\n -> appEndo . foldMap Endo . replicate n
Вариант ответа trinithis с помощью пакета newtype, просто для удовольствия:
(\n f -> under Endo (mconcat . replicate n) f)
Или без точек:
under Endo . (mconcat .) . replicate
Вот версия, которая имеет сложность O (log n) вместо O (n) (для построения функции, а не для ее применения):
composeN 0 f = id
composeN n f
| even n = g
| odd n = f . g
where g = g' . g'
g' = composeN (n 'div' 2) f
Другое решение с использованием foldr
:
\n → flip (foldr ($)). replicate n
iterate (f .) id !! n
или
iterate (f .) f !! (n-1)
в зависимости от того, разрешено ли n == 0
.