// event_writer.mbt
//! 专门用于事件累积的 Writer

///|
pub struct EventWriter[E, A] {
  run : () -> (A, Array[E])
}

///|
pub fn[E, A] EventWriter::new(run : () -> (A, Array[E])) -> EventWriter[E, A] {
  EventWriter::{ run, }
}
// impl[E, A] EventWriter[E, A] {

///|
/// 纯值
pub fn[E, A] EventWriter::pure(value : A) -> EventWriter[E, A] {
  EventWriter::new(fn() { (value, []) })
}

///|
/// 产生单个事件
pub fn[E] EventWriter::tell(event : E) -> EventWriter[E, Unit] {
  EventWriter::new(fn() { ((), [event]) })
}

///|
/// 产生多个事件
pub fn[E] EventWriter::tell_many(events : Array[E]) -> EventWriter[E, Unit] {
  EventWriter::new(fn() { ((), events) })
}

///|
/// 组合
pub fn[E, A, B] EventWriter::bind(
  self : EventWriter[E, A],
  f : (A) -> EventWriter[E, B],
) -> EventWriter[E, B] {
  EventWriter::new(fn() {
    let (val, events1) = (self.run)()
    let (new_val, events2) = (f(val).run)()
    (new_val, events1 + events2)
  })
}

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

///|
/// 执行
pub fn[E, A] EventWriter::run_writer(self : EventWriter[E, A]) -> (A, Array[E]) {
  (self.run)()
}

///|
pub fn[E, A] EventWriter::eval(self : EventWriter[E, A]) -> A {
  (self.run)().0
}

///|
pub fn[E, A] EventWriter::exec(self : EventWriter[E, A]) -> Array[E] {
  (self.run)().1
}
// }

// 工具函数

///|
pub fn[E, A] EventWriter::sequence(
  writers : Array[EventWriter[E, A]],
) -> EventWriter[E, Array[A]] {
  let init = EventWriter::pure([])
  writers.fold(init~, fn(acc, w) {
    acc.bind(fn(arr) { w.map(fn(a) { arr + [a] }) })
  })
}

///|
pub fn[E, A, B] EventWriter::traverse(
  arr : Array[A],
  f : (A) -> EventWriter[E, B],
) -> EventWriter[E, Array[B]] {
  EventWriter::sequence(arr.map(f))
}