Почему компилятор F # предпочитает генерировать закрытые реализации типов FSharpFunc? - PullRequest
0 голосов
/ 30 июня 2018

Для этого кода:

module Module =
    let func x y z = 0

    [<EntryPoint>]
    let main args =
        func 1
        func 1 1
        0

Выход декомпиляции:

[CompilationMapping(SourceConstructFlags.Module)]
public static class Main
{
    [CompilationMapping(SourceConstructFlags.Module)]
    public static class Module
    {
        [Serializable]
        internal sealed class main@30 : OptimizedClosures.FSharpFunc<object, object, int>
        {
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            [CompilerGenerated]
            [DebuggerNonUserCode]
            public int x;

            [CompilerGenerated]
            [DebuggerNonUserCode]
            internal main@30(int x)
            {
                this.x = x;
            }

            public override int Invoke(object y, object z)
            {
                return func(x, y, z);
            }
        }

        [Serializable]
        internal sealed class main@31-1 : FSharpFunc<object, int>
        {
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            [CompilerGenerated]
            [DebuggerNonUserCode]
            public int x;

            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            [CompilerGenerated]
            [DebuggerNonUserCode]
            public int y;

            [CompilerGenerated]
            [DebuggerNonUserCode]
            internal main@31-1(int x, int y)
            {
                this.x = x;
                this.y = y;
            }

            public override int Invoke(object z)
            {
                return func(x, y, z);
            }
        }

        [CompilationArgumentCounts(new int[]
        {
            1,
            1,
            1
        })]
        public static int func<a, b, c>(a x, b y, c z)
        {
            return 0;
        }

        [EntryPoint]
        public static int main(string[] args)
        {
            int x = 1;
            new main@30(x);
            int x2 = 1;
            int y = 1;
            new main@31-1(x2, y);
            return 0;
        }
    }

    public static a Dump<a>(a arg00)
    {
        return arg00.Dump();
    }
}

Генерирует конкретный тип, то есть общие параметры предоставляются при определении типа. Почему это не делается на этапе строительства? Я также заметил, что типы генерируются в модуле, где происходит вызов, а не там, где определено func.

Имея let func x y z = ..., нам нужны реализации типов, чтобы охватить все возможности:

FSharpFunc<T1,FSharpFunc<T2,T3,TReturn>>
FSharpFunc<T1,T2,FSharpFunc<T3,TReturn>>
FSharpFunc<T1,FSharpFunc<T2,FsharpFunc<T3,TReturn>>>

Компилятор может генерировать все возможные комбинации в том же месте, где определена функция, закрываясь только для параметров с зависимыми типами.

Можно утверждать, что для списка из 7 аргументов набор типов будет довольно большим, но такие типы, как FSharpFunc<T1,T2,..,Tn, FSharpFunc<...>>, являются простой оптимизацией. И FSharpFunc поддерживает до шести универсальных типов, тогда компилятор должен переключиться на FSharpFun<T1,T2,T3,T4,T5,FSharp<...>>.

1 Ответ

0 голосов
/ 01 июля 2018

Как указал Федор, компилятор генерирует скрытые классы не созданием функций. Скрытые классы используются для частичного применения.

В F # частичное приложение и лямбда-выражения реализованы как сгенерированный компилятором класс, расширяющий абстрактный класс. C # лямбды вместо этого полагаются на делегатов. IIRC Java и Scala используют технику, аналогичную F #, поскольку у JVM нет делегатов.

Я подозреваю, что компилятор F # генерирует класс для частичного приложения, потому что это проще, чем собирать все частичные приложения и объединять идентичные.

Также помогает отладка программ F #, поскольку имя подсказывает, где было выполнено частичное приложение: main@31-1 => В основной функции в строке 31. Это имя, если оно включено в журналы или прогоны производительности, может помочь определить, какое частичное приложение вызывает проблемы.

Это происходит за счет увеличения размера файла сборки F #, как отмечено в комментарии Павла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...