我想说的最好的问题不是我们怎么称呼它,而是我们如何分析这样的一段代码。在这种分析中,我的第一个关键问题是:
- 副作用是取决于函数的参数还是副作用的结果?
- 否: “有效功能”可以重构为纯功能,有效动作和组合它们的机制。
- 是: “有效函数”是产生单子结果的函数。
这很容易在Haskell中进行说明(而这句话只是一个笑话而已)。例如,“否”的情况如下所示:
double :: Num a => a -> IO a
double x = do
putStrLn "I'm doubling some number"
return (x*2)
在此示例中,我们采取的操作(打印行"I'm doubling some number"
)x
对结果之间的关系没有影响。这意味着我们可以通过这种方式(使用Applicative
类及其*>
运算符)对其进行重构,这表明函数和效果实际上是正交的:
double :: Num a => a -> IO a
double x = action *> pure (function x)
where
-- The pure function
function x = x*2
-- The side effect
action = putStrLn "I'm doubling some number"
因此,在这种情况下,我个人会说,这是您可以分解出纯函数的情况。许多Haskell编程都与此有关-学习如何从有效代码中剔除纯净的部分。
“是”排序的示例,其中纯净部分和有效部分不正交:
double :: Num a => a -> IO a
double x = do
putStrLn ("I'm doubling the number " ++ show x)
return (x*2)
现在,您打印的字符串取决于的值x
。但是,函数部分(乘以x
2)完全不依赖于效果,因此我们仍然可以将其分解出来:
logged :: (a -> b) -> (a -> IO x) -> IO b
logged function logger a = do
logger a
return (function a)
double x = logged function logger
where function = (*2)
logger x putStrLn ("I'm doubling the number " ++ show x)
我可以继续阐明其他示例,但是我希望这足以说明我的出发点:您不要“称呼”它,您要分析纯净的部分和有效的部分之间的联系,并在它们存在时予以分解。对你有利。
这是Haskell Monad
如此广泛使用其类的原因之一。Monads(除其他外)是执行这种分析和重构的工具。