// writer.mbt
//! Writer Monad - 用于累积日志/事件

/// Writer Monad 类型
// pub struct Writer[W, A] {
//   run : () -> (A, W)
// }

///|
/// Writer Monad 类型
pub struct Writer[W, A] {
  run : () -> (A, W)
  config : WriterConfig[W]
}

///|
pub struct WriterConfig[W] {
  empty : W
  concat : (W, W) -> W
}
/// Builder 模式
// pub struct WriterBuilder[W, A] {
//   empty : W
//   concat : (W, W) -> W
//   value : Option[A]
//   log : Option[W]
// }

///|
pub fn[W] Writer::new(empty : W, concat : (W, W) -> W) -> WriterConfig[W] {
  WriterConfig::{ empty, concat, }
}

///|
pub fn[W, A] Writer::pure(value : A, config : WriterConfig[W]) -> Writer[W, A] {
  { run: fn() { (value, config.empty) }, config, }
}

///|
/// 产生日志
pub fn[W] Writer::tell(log : W, config : WriterConfig[W]) -> Writer[W, Unit] {
  { run: fn() { ((), log) }, config, }
}

///|
/// 组合
pub fn[W, A, B] Writer::bind(
  self : Writer[W, A],
  f : (A) -> Writer[W, B],
) -> Writer[W, B] {
  let config = self.config
  {
    run: fn() {
      let (val, log1) = (self.run)()
      let writer2 = f(val)
      let (new_val, log2) = (writer2.run)()
      (new_val, (config.concat)(log1, log2))
    },
    config,
  }
}

///|
/// 映射
pub fn[W, A, B] Writer::map(self : Writer[W, A], f : (A) -> B) -> Writer[W, B] {
  self.bind(fn(a) { Writer::pure(f(a), self.config) })
}

///|
/// 执行并获取结果和日志
pub fn[W, A] Writer::run_writer(self : Writer[W, A]) -> (A, W) {
  (self.run)()
}

///|
/// 执行并只获取值
pub fn[W, A] Writer::eval(self : Writer[W, A]) -> A {
  (self.run)().0
}

///|
/// 执行并只获取日志
pub fn[W, A] Writer::exec(self : Writer[W, A]) -> W {
  (self.run)().1
}