@open @abstract class Option[T] { @open @abstract fun is_some() -> Bool; @open @abstract fun is_none() -> Bool; @open @abstract fun has(rhs: T) -> Bool; @open @abstract fun unwrap() -> T; } class Some[T](let wrapped: T): Option[T] { @override fun is_some() -> Bool = true; @override fun is_none() -> Bool = false; @override fun has(rhs: T) -> Bool = self.wrapped === rhs; @override fun unwrap() -> T { self.wrapped } } class None[T]: Option[T] { @override fun is_some() -> Bool = false; @override fun is_none() -> Bool = true; @override fun has(rhs: T) -> Bool = false; @override fun unwrap() -> T { fatalError("cannot unwrap None."); defaultValue[T]() } } fun none[T]() -> Option[T] = None[T](); fun some[T](wrapped: T) -> Option[T] = Some[T](wrapped); fun optionContains[T: Equals](lhs: Option[T], rhs: T) -> Bool { if lhs.is_some() { let lhs = lhs.unwrap(); lhs === rhs || lhs.equals(rhs) } else { false } } fun optionEquals[T: Equals](lhs: Option[T], rhs: Option[T]) -> Bool { if lhs.is_some() { if rhs.is_some() { let lhs = lhs.unwrap(); let rhs = rhs.unwrap(); lhs.equals(rhs) } else { false } } else { rhs.is_none() } } fun optionToString[T: Stringable](lhs: Option[T]) -> String { if lhs.is_some() { "Some(${lhs.unwrap()})" } else { "None" } }