我正在学习函数式编程,并尝试以函数式方式解决几个问题。在将问题分解为函数时,我经历过的一件事是,似乎我有两个选择:使用具有相似参数列表的几个不同的函数,或者使用嵌套函数,作为闭包,它们可以简单地引用父函数中的绑定。
虽然我最终采用了第二种方法,因为它使函数调用更小并且看起来“感觉”更好,从我的阅读中看起来似乎我可能缺少函数式编程的一个要点,因为这似乎“副作用”?现在被授予,这些嵌套函数不能修改外部绑定,因为我使用的语言阻止了它,但是如果你看一下每个单独的内部函数,你不能说“给定相同的参数,这个函数将返回相同的结果”因为他们确实使用了父范围内的变量......我是对的吗?
进行什么是理想的方式?
谢谢!
答案 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函数确实无法区分!)您是否会认为上述代码是“副作用”或因此无效?