///|
pub(all) type Prediate[A] ((A) -> Bool, &Show)

///|
pub fn[A] Prediate::to_string(self : Prediate[A]) -> String {
  "Prediate(\{self._.1.to_string()})"
}

///|
pub impl[A] Show for Prediate[A] with output(
  breaker : Prediate[A],
  logger : &Logger
) -> Unit {
  logger.write_string(breaker.to_string())
}

///|
pub impl[A] Alt for Prediate[A] with lor(self, orw) -> Prediate[A] {
  Prediate(
    (
      fn(arg) { (self._.0)(arg) || (orw._.0)(arg) },
      "(\{self._.1} | \{orw._.1})",
    ),
  )
}

///|
pub fn[A] Prediate::land(self : Prediate[A], orw : Prediate[A]) -> Prediate[A] {
  Prediate(
    (
      fn(arg) { (self._.0)(arg) && (orw._.0)(arg) },
      "(\{self._.1} * \{orw._.1})",
    ),
  )
}

///|
pub fn[A] Prediate::op_neg(self : Prediate[A]) -> Prediate[A] {
  Prediate((fn(arg) { (self._.0)(arg) |> not }, "!(\{self._.1})"))
}

///|
pub fn[A] Prediate::op_get(self : Prediate[A], arg : A) -> Bool {
  (self._.0)(arg)
}