Quels sont les effets secondaires sur les performances de la définition de fonctions dans une fonction récursive par rapport à l'extérieur dans F #

Si vous avez une fonction récursive qui s'appuie sur une autre fonction, quelle est la méthode préférée pour l'implémenter?

1) en dehors de la fonction récursive

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

2) à l'intérieur de la fonction récursive

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

3) encapsuler à la fois dans une troisième fonction

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

4) quelque chose d'encore mieux?

6
Pourquoi le vote serré? Cela semble être une très bonne/raisonnable question.
ajouté l'auteur Daniel, source

1 Réponses

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

Se traduit par:

[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);
        }
    }
}

Le seul coût supplémentaire pour une fonction interne est la création d’une instance de FSharpFunc - semble négligeable.

Sauf si vous êtes très sensible aux performances, j'utiliserais la portée qui a le plus de sens, c'est-à-dire la portée la plus étroite possible.

5
ajouté
Voir la dernière phrase. Je n'ai pas le temps de le comparer, mais j'ai mentionné la seule différence notable.
ajouté l'auteur Daniel, source
La réponse pourrait être déduite de vos extraits, mais vous devriez vraiment le préciser.
ajouté l'auteur Ramon Snir, source
La création d'un FSharpFunc pourrait nuire aux performances en cas d'utilisation intensive du code, mais dans la plupart des cas cela n'aurait aucune importance.
ajouté l'auteur Ramon Snir, source