Показатели производительности стиля Point-Free - программирование
Подтвердить что ты не робот

Показатели производительности стиля Point-Free

Im, берущий мои первые детские шаги в обучении функциональной программированию с использованием F # и Ive, просто встречается с операторами Forward Pipe (| > ) и Forward Composition ( → ). Сначала я думал, что они были просто сахаром, а не влияют на конечный код (хотя я знаю, что трубопровод помогает с типом вывода).

Однако я столкнулся с этой статьей SO: Каковы преимущества и недостатки стиля "point free" в функциональном программировании? Что имеет два интересных и информативных ответа (что вместо упрощения вещей для меня открыло целую банку червей, окружающих "точечный" или "бессмысленный" стиль). Мой прием от этих (и других чтений) - это то, что без точек является обсуждаемой областью. Как и lambas, стиль без точек может сделать код более понятным или намного сложнее, в зависимости от использования. Это может помочь в значительном именовании вещей.

Но мой вопрос касается комментария к первому ответу: AshleyF размышляет в ответе:

"Мне кажется, что композиция может уменьшить давление в ГК, сделав более очевидным для компилятора то, что нет необходимости производить промежуточные значения, как при конвейерной обработке, что помогает сделать так называемую проблему" обезлесения "более приемлемой".

Gasche отвечает:

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

Может ли кто-нибудь расширить влияние на производительность? (В общем и конкретно для F #) я только что предположил, что это была вещь в стиле письма, и компилятор будет переводить обе идиомы в эквивалентный код.

4b9b3361

Ответ 1

Этот ответ будет F # -специфичным. Я не знаю, как работают внутренние функции других функциональных языков, и тот факт, что они не компилируются в CIL, может иметь большое значение.

Здесь я вижу три вопроса:

  • Каковы последствия использования |>?
  • Каковы последствия использования >>?
  • Какова разница в производительности между объявлением функции с ее аргументами и без них?

Ответы (используя примеры из вопроса, который вы связали с):

  • Есть ли разница между x |> sqr |> sum и sum (sqr x)?

    Нет, нет. Скомпилированный CIL точно такой же (здесь представлен в С#):

    sum.Invoke(sqr.Invoke(x))
    

    (Invoke() используется, потому что sqr и sum не являются методами CIL, они FSharpFunc, но это не имеет значения здесь.)

  • Есть ли разница между (sqr >> sum) x и sum (sqr x)?

    Нет, оба образца скомпилируются с тем же CIL, что и выше.

  • Есть ли разница между let sumsqr = sqr >> sum и let sumsqr x = (sqr >> sum) x?

    Да, скомпилированный код отличается. Если вы укажете аргумент, sumsqr будет скомпилирован в обычный метод CLI. Но если вы не укажете его, он скомпилируется как свойство типа FSharpFunc с полем поддержки, метод Invoke() содержит код.

    Но эффект всего заключается в том, что вызов бесплатной версии означает загрузку одного поля (FSharpFunc), которое не выполняется, если вы укажете аргумент. Но я думаю, что это не должно заметно влиять на производительность, за исключением самых экстремальных обстоятельств.