3

我是 Scala 编程的新手。我现在很困惑如何以异步和函数的方式声明一个 biz 方法,方法实现应该包含许多日志消息。作为一种不好的做法,我这样编写代码:

// trait
trait StoreService {
    def create[Config]: Kleisli[Future, Config, Store]
}

// and the interpreter
trait StoreServiceInterpreter extends StoreService {
    def create[Config]: Kleisli[Future, Config, Store] = Kleisli {cfg => 
        // some implementation ...
        log.info("bla bla bla ...")
        // some implementation ...
        // return a store
        Store(...)
    }
}

这很糟糕,因为实现是有副作用的,在这个地方记录一些东西。所以,我像这样更改方法声明:

// trait
trait StoreService {
    def create[Config]: Kleisli[Future, Config, Writer[Vector[String], Store]]
}

// and the interpreter
trait StoreServiceInterpreter extends StoreService {
    def create[Config]: Kleisli[Future, Config, Writer[Vector[String], Store]] = Kleisli {cfg => 
        // some implementation ...
        // log.info("bla bla bla ...")
        // some implementation ...
        // return a store
        Writer(Vector("bla bla bla...", Store(...))
    }
}

使用Writer,消除了副作用,但代码不清楚:

  • 为什么作家回来了?Writer[Vector[String], Store]有比 更多的噪音Store,有什么办法可以避免样板代码并保持无副作用?
  • 写入log不是临时的!我应该构建一个字符串向量来保存消息,使用:+++操作来添加日志。我认为这不是临时日志记录,就像log.info(...)在任何地方写一样。
4

1 回答 1

1

为方便起见,我认识的大多数 Scala 开发人员倾向于将日志记录视为“非副作用”。但是,如果你真的想跟踪它们,你可能想看看“free monad”的概念。更多信息: 一般描述记录示例

我的粗略解释是“让我们将我们的程序建模为一些 AST 并解释它”。因此,在 AST 中,您定义了“日志记录”的概念,但没有定义实现,稍后会在解释中出现。这种方法允许您密切关注日志记录并更改操作(从写入 /dev/null 到异步发布到外部服务),而不会影响代码的“业务”部分。

于 2017-06-12T07:56:14.767 回答