26

我更喜欢尽可能地坚持功能范式,当我的大脑准备好迎接挑战时,我会尽可能接近纯粹的功能范式。我尽可能使用 F#。通常,我会使用 VB.NET 或 C#(或 VBA,当我真的很不走运时)。所以我的语言让我远离了函数式方法。

从历史上看,在我得到结果之前,我一直忽略记录和与用户的沟通——让用户等待。现在我正在尝试实现状态栏的日志记录和/或更新。这很容易,因为我的语言允许我随时写入标准输出。但从纯粹的功能角度来看,如何将有关功能内部发生的信息泄露给外部世界?在计算过程中记录或与用户通信是否与纯粹的功能方法相反?

我确信在 Haskell 中会使用 Monad。使用其他语言时怎么办?

谢谢。

4

2 回答 2

9

让我们看一下 Haskell 的一元解决方案。日志记录背后的想法是,我们的计算有一个额外的方法,可以在某处“输出”写入一条消息。有很多方法可以表示这样的计算,但最通用的方法之一是创建一个 monad:

class (Monad m) => MonadWriter w m | m -> w where
    tell   :: w -> m ()

类型w代表消息,功能tell是将消息“发送”到单子(效果完整)计算中。

笔记:

  • HaskellMonadWriter实际上更丰富,它包含允许检查和修改的函数w,但我们暂时先把它放在一边。
  • | m -> w部分对于解释并不重要,它只是意味着w对于给定的m.

最常用的实现是Writer,它基本上只是一对。其中一个元素是计算的结果,另一个元素是一系列书面消息。(实际上它并不是一个真正的序列,它更通用 - 一个幺半群,它定义了将多个消息组合成一个的操作。)您可以通过查看Writer 模块来检查 Haskell 的解决方案。然而,它更普遍地使用WriterTmonad 转换器编写,所以如果你不是 monad 粉丝,它可能很难阅读。同样的事情也可以在其他函数式语言中完成,例如在 Scala 中查看这个示例

但是上述类型类还有其他可能的、更多面向副作用的(仍然有效的)实现。我们可以定义tell将消息发送到某个外部接收器,例如标准输出、文件等。例如:

{-# LANGUAGE FunctionalDependencies, TypeSynonymInstances, FlexibleInstances #-}

instance MonadWriter String IO where
    tell = putStrLn

在这里,我们说它IO可以用作将Strings 写入标准输出的日志记录工具。(这只是一个简化的例子,一个完整的实现可能会有一个 monad 转换器,可以tell为任何IO基于 - 的 monad 添加功能。)

于 2012-12-08T22:19:45.337 回答
5

我是函数式编程的新手,但这是 Scala 的尝试:

object FunctionalLogging {

  type Result = Int

  class ResultWithLogging(val log: List[String], val result: Result) {}

  def functionWithLogging(log: List[String], arg: String): ResultWithLogging = {
    def function(arg: String): Result = arg.length

    new ResultWithLogging(log :+ ("Calling function(" + arg +")"), function(arg))
  }

  val result = functionWithLogging(List(), "Hello world!")

  // -- Pure functional code ends here --
  println("Result = " + result.result)
  println("Log = " + result.log)
}

它的功能性在于没有副作用,但显然日志是函数参数和返回的一部分,因此它不是很优雅或实用。

在我看来,根据定义,日志记录是一种可取的副作用,所以如果你同意我的定义,问题是如何将非功能性代码与功能性代码隔离开来。在实践中,我可能会从一个 Scala 对象开始(可能太像一个单例 - 一个 trait 可能是更好的 Scala),或者一个演员来积累日志消息并做任何需要用它们做的事情。

这是一个更务实的观点:Logging in Scala

编辑

这个问题谈到了 Haskell Monads 和 IO:除了 Monads 之外,还有哪些其他方式可以用纯函数式语言处理状态?

于 2012-12-07T22:08:59.117 回答