Logging 从函数式编程范例中进行日志记录

Logging 从函数式编程范例中进行日志记录,logging,functional-programming,purely-functional,Logging,Functional Programming,Purely Functional,我更喜欢尽可能地坚持功能范式,当我的大脑准备迎接挑战时,尽可能地接近纯功能范式。如果可能的话,我会用F。通常,我会被VB.NET或C#(或者VBA,当我真的很不走运的时候)。因此,我的语言让我远离了函数式方法 历史上,我忽略了日志记录和与用户的通信,直到得到结果——让用户等待。现在我正在尝试实现状态栏的日志记录和/或更新。这很容易,因为我的语言允许我在任何时候都可以写入标准输出。但是,从纯粹的功能角度来看,一个人如何向外界泄露自己功能内部的信息呢?在计算过程中记录日志或与用户通信是否与纯功能方法

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

历史上,我忽略了日志记录和与用户的通信,直到得到结果——让用户等待。现在我正在尝试实现状态栏的日志记录和/或更新。这很容易,因为我的语言允许我在任何时候都可以写入标准输出。但是,从纯粹的功能角度来看,一个人如何向外界泄露自己功能内部的信息呢?在计算过程中记录日志或与用户通信是否与纯功能方法完全相反

我相信在哈斯克尔,人们会用单子。使用其他语言的时候呢


谢谢。

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

对象函数记录{
类型结果=Int
类ResultWithLogging(val log:List[String],val result:result){}
def functionWithLogging(日志:列表[String],参数:String):ResultWithLogging={
def函数(arg:String):结果=arg.length
新结果日志(日志:+(“调用函数(“+arg+”))、函数(arg))
}
val result=functionWithLogging(List(),“Hello world!”)
//--纯函数代码到此结束--
println(“Result=“+Result.Result”)
println(“Log=“+result.Log”)
}
它的功能在于没有副作用,但很明显,日志是函数参数和返回的一部分,所以它不是很优雅或实用

在我看来,从定义上讲,日志记录是一种可取的副作用,因此,如果您同意我的定义,那么问题是如何将非功能性代码与功能性代码隔离开来。在实践中,我可能会从一个Scala对象(可能太像一个singleton——trait可能比Scala更好)或一个参与者开始,以积累日志消息并对其执行任何需要执行的操作

这是一种更加务实的观点:

编辑

这个问题是关于哈斯克尔单子和IO的:

让我们看看哈斯克尔的一元溶液。日志背后的想法是,我们的计算有一个额外的方法,可以将消息写到“out”的某个地方。有许多方法可以表示这种计算,但最常用的方法之一是制作单子:

class(Monad m)=>MonadWriter w m | m->w where
告诉::w->m()
类型
w
表示消息,函数
tell
是将消息“发送”到一元(效果完全)计算中的函数

注:

  • Haskell的
    MonadWriter
    实际上更丰富,它包含允许检查和修改
    w
    的函数,但现在我们暂且不谈这些
  • |m->w
    部分对于解释来说并不重要,它只是意味着
    w
    对于给定的
    m
    是固定的
最常用的实现是
Writer
,它基本上只是一对。其中一个元素是计算的结果,另一个元素是一系列书面消息。(实际上,它不是一个真正的序列,它更一般——一个monoid,它定义了将多条消息组合成一条消息的操作。)您可以通过查看。不过,它是使用
WriterT
monad transformer编写的,所以如果您不是monad迷,它可能很难阅读。同样的事情也可以在其他函数式语言中完成,例如,请参见

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

{-#语言功能相关、类型同义词实例、FlexibleInstances}
实例MonadWriter字符串IO,其中
tell=putStrLn

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

我更喜欢尽可能地坚持功能范式,当我的大脑准备迎接挑战时,尽可能地接近纯粹的功能性内容
当它给你带来一些好处时使用它。纯功能代码通常会给系统带来意外的复杂性。这可能是一个很好的建议……我喜欢你在这里的思考过程。不过,在我的例子中,该函数运行时间相当长,我希望在处理过程中进行报告,而不是等待其返回以报告其日志。然而,如果没有其他人回答我的问题,我可能会将此标记为答案,因为虽然Haskell的答案很好,但我的问题更具体地说是关于非单子方法。谢谢类和对象?什么?这不是函数式编程范式,这只是FP中的OOP。我不明白重点,Haskell中的类型类与OO类有很大不同。谢谢。也许我也不明白这一点。在这个答案中,没有类的用例。请关注日志使用的客户端,而不是库。非常感谢。了解日志类型如何传递给函数并用于创建和返回日志描述是很有趣的。我的意思是绝对纯代码的一部分,没有任何副作用。结果应聚合在一起并传递给实际的记录器副作用执行者?在最高级别/一些中间级别,但绝对不是在应用程序函数内部。日志记录结果应仅为comm