2008-11-22 4 views
5

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

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

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

Спасибо!

ответ

2

Функции гнездования - отличный способ разделить труд во многих функциях. Это не очень «побочно»; если это помогает, подумайте о захваченных переменных как о неявных параметрах.

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

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.

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

+0

facHelper фактически не относится к каким-либо внешним значениям - он по-прежнему чисто функциональный. – 2008-11-22 07:28:33

3

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

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

(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)) 

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

1

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^