Вложенные функции:Неправильное использование побочных эффектов?

StackOverflow https://stackoverflow.com/questions/310964

Вопрос

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

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

Каков желательный способ действий?

Спасибо!

Это было полезно?

Решение

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

Одним из примеров, когда вложенные функции полезны, является замена циклов.Параметры вложенной функции могут действовать как индуктивные переменные, которые накапливают значения.Простой пример:

let factorial n =
    let rec facHelper p n =
        if n = 1 then p else facHelper (p*n) (n-1)
    in
    facHelper 1 n

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

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

Другие советы

Функциональное программирование - это не все или ничего.Если бы вложение функций имело больше смысла, я бы выбрал такой подход.Однако, если вы действительно хотите, чтобы внутренние функции были чисто функциональными, явно передайте в них все необходимые параметры.

Вот небольшой пример на схеме:

(define (foo a)
  (define (bar b)
    (+ a b))      ; getting a from outer scope, not purely functional
  (bar 3))

(define (foo a)
  (define (bar a b)
    (+ a b))      ; getting a from function parameters, purely functional
  (bar a 3))


(define (bar a b) ; since this is purely functional, we can remove it from its
  (+ a b))        ; environment and it still works

(define (foo a)
  (bar a 3))

Лично я бы выбрал первый подход, но любой из них будет работать одинаково хорошо.

Рассмотрим следующий (надуманный) Фрагмент Haskell:

putLines :: [String] -> IO ()
putLines lines = putStr string
    where string = concat lines

string является локально связанной именованной константой.Но разве это также не функция, не принимающая аргументов, которая закрывается поверх lines и, следовательно, является референциально непрозрачным?(В Haskell константы и нулевые функции действительно неразличимы!) Считаете ли вы приведенный выше код “побочным эффектом” или нефункциональным из-за этого?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top