Які побічні ефекти від визначення функцій всередині рекурсивної функції проти зовні в F #

Якщо у вас є рекурсивна функція, яка спирається на яку-небудь іншу функцію, що є кращим способом реалізації цього?

1) поза рекурсивної функції

let doSomething n = ...
let rec doSomethingElse x =
    match x with
    | yourDone -> ...
    | yourNotDone -> doSomethingElse (doSomething x)

2) всередині рекурсивної функції

let rec doSomethingElse x =
    let doSomething n = ...
    match x with
    | yourDone -> ...
    | yourNotDone -> doSomethingElse (doSomething x)

3) інкапсулювати як всередині третьої функції

let doSomethingElse x =
    let doSomething n = ...
    let innerDoSomethingElse =
        match x with
        | yourDone -> ...
        | yourNotDone -> innerDoSomethingElse (doSomething x)

4) щось ще краще?

6
Чому близьке голосування? Це здається дуже хорошим/розумним питанням.
додано Автор Daniel, джерело

1 Відповіді

module Test =

    let f x = 
      let add a b = a + b //inner function
      add x 1

    let f2 x =
      let add a = a + x //inner function with capture, i.e., closure
      add x

    let outerAdd a b = a + b

    let f3 x =
      outerAdd x 1

Перекладає на:

[CompilationMapping(SourceConstructFlags.Module)]
public static class Test {

    public static int f(int x) {
        FSharpFunc> add = new [email protected]();
        return FSharpFunc.InvokeFast(add, x, 1);
    }

    public static int f2(int x) {
        FSharpFunc add = new [email protected](x);
        return add.Invoke(x);
    }

    public static int f3(int x) {
        return outerAdd(x, 1);
    }

    [CompilationArgumentCounts(new int[] { 1, 1 })]
    public static int outerAdd(int a, int b) {
        return (a + b);
    }

    [Serializable]
    internal class [email protected] : OptimizedClosures.FSharpFunc {
        internal [email protected]() { }

        public override int Invoke(int a, int b) {
            return (a + b);
        }
    }

    [Serializable]
    internal class [email protected] : FSharpFunc {
        public int x;

        internal [email protected](int x) {
            this.x = x;
        }

        public override int Invoke(int a) {
            return (a + this.x);
        }
    }
}

Єдиною додатковою вартістю для внутрішньої функції є нове виведення екземпляра FSharpFunc - здається незначним.

Якщо ви дуже не чутливі до продуктивності, я маю на увазі той обсяг, який має найбільший сенс, тобто можливу вузьку область.

5
додано
Див. Останнє речення. У мене немає часу на тестування, але я згадав лише помітну різницю.
додано Автор Daniel, джерело
Відповідь може бути виведена з ваших фрагментів, але ви дійсно повинні це написати.
додано Автор Ramon Snir, джерело
Створення FSharpFunc може призвести до пошкодження продуктивності для важкого використання коду, але для більшості випадків це не має значення.
додано Автор Ramon Snir, джерело