嵌套功能:副作用使用不当?

时间:2008-11-22 06:40:57

标签: functional-programming nested side-effects

我正在学习函数式编程,并尝试以函数式方式解决几个问题。在将问题分解为函数时,我经历过的一件事是,似乎我有两个选择:使用具有相似参数列表的几个不同的函数,或者使用嵌套函数,作为闭包,它们可以简单地引用父函数中的绑定。

虽然我最终采用了第二种方法,因为它使函数调用更小并且看起来“感觉”更好,从我的阅读中看起来似乎我可能缺少函数式编程的一个要点,因为这似乎“副作用”?现在被授予,这些嵌套函数不能修改外部绑定,因为我使用的语言阻止了它,但是如果你看一下每个单独的内部函数,你不能说“给定相同的参数,这个函数将返回相同的结果”因为他们确实使用了父范围内的变量......我是对的吗?

进行什么是理想的方式?

谢谢!

3 个答案:

答案 0 :(得分:3)

功能编程不是全有或全无。如果嵌套函数更有意义,我会采用这种方法。但是,如果您确实希望内部函数纯粹是功能性的,请将所有必需的参数显式传递给它们。

这是Scheme中的一个小例子:

(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 :(得分: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参数。

但请注意,单独测试嵌套函数可能很困难,因为它们不能在父元素之外引用。

答案 2 :(得分:1)

考虑以下(设计的)Haskell片段:

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

string是一个局部绑定的命名常量。但是它不是一个不接受lines关闭的参数的函数,因此是不明确的不透明的吗? (在Haskell中,常量和nullary函数确实无法区分!)您是否会认为上述代码是“副作用”或因此无效?