Как мне реализовать функцию `apply_n_times`? - PullRequest
2 голосов
/ 05 августа 2020

Как мне реализовать функцию apply_n_times, которая получает функцию f: T -> T и число n, и результатом будет функция, которая применяет f n раз?

Например apply_n_times(f, 0) равно |x| x и apply_n_times(f, 3) равно |x| f(f(f(x))).

В этой функции нет более глубокого смысла, я просто хочу реализовать ее для обучения.

Мой текущий код:

fn apply_n_times<T>(f: Fn(T) -> T, n: i32) -> dyn Fn(T) -> T {
    if n < 0 {
        panic!("Cannot apply less than 0 times!");
    }

    if n == 1 {
        |x: T| x
    } else {
        |x| f(apply_n_times(f, n - 1)(x))
    }
}

fn times_two(n: i32) -> i32 {
    return n * 2;
}

fn main() {
    println!("{}", apply_n_times(times_two, 0)(3));
    println!("{}", apply_n_times(times_two, 1)(3));
    println!("{}", apply_n_times(times_two, 3)(3));
}

Я нахожусь в 13 главе книги Rust, но я немного заглянул вперед. Мне, наверное, придется вернуть Box, но я не совсем уверен. Я попробовал, и у меня ничего не вышло.

Я тоже хотел изменить подпись на эту, но это только приводит к проблемам:

fn apply_n_times<F, T>(f: F, n: i32) -> F
where
    F: Fn(T) -> T,

К сожалению, ошибки компилятора мне не помогают; говорят что не так на низком уровне, а я бегала по кругу.

1 Ответ

10 голосов
/ 05 августа 2020
fn apply_n_times<T>(f: impl Fn(T) -> T, n: usize) -> impl Fn(T) -> T {
    move |arg| (0..n).fold(arg, |a, _| f(a))
}

Использование usize позволяет избежать отрицательной проверки. Рассмотрите возможность использования FnMut вместо Fn, так как это более гибко для пользователей функции.

См. Также:

...