A MoonBit library providing the Either type for representing values with two possible types, inspired by Rust's either and Haskell's either libraries.
///|
test "creating either values" {
// Create Left and Right values
let left_val : Either[Int, String] = left(42)
let right_val : Either[Int, String] = right("hello")
// Using constructors directly
let left_direct : Either[Int, Unit] = Left(42)
let right_direct : Either[Unit, String] = Right("hello")
assert_true(left_val is Left(42))
assert_true(right_val is Right("hello"))
assert_true(left_direct is Left(42))
assert_true(right_direct is Right("hello"))
}///|
test "checking variants" {
let values : Array[Either[Int, String]] = [Left(1), Right("two"), Left(3)]
// Using is_left() and is_right()
assert_true(values[0].is_left())
assert_true(values[1].is_right())
assert_false(values[2].is_right())
// Using pattern matching with `is` (preferred)
assert_true(values[0] is Left(_))
assert_true(values[1] is Right(_))
assert_false(values[2] is Right(_))
}///|
test "extracting values" {
let left_val : Either[Int, String] = Either::Left(42)
let right_val : Either[Int, String] = Either::Right("hello")
// Extract as Option
assert_true(left_val.left() is Some(42))
assert_true(left_val.right() is None)
assert_true(right_val.right() is Some("hello"))
assert_true(right_val.left() is None)
// Extract with default values
assert_eq(left_val.left_or(0), 42)
assert_eq(left_val.right_or("default"), "default")
assert_eq(right_val.left_or(0), 0)
assert_eq(right_val.right_or("default"), "hello")
}///|
test "mapping operations" {
let left : Either[Int, String] = Left(10)
let right : Either[Int, String] = Right("hello")
// Map left side only
let mapped_left = left.map_left(x => x * 2)
assert_true(mapped_left is Left(20))
// Map right side only
let mapped_right = right.map_right(s => s + " world")
assert_true(mapped_right is Right("hello world"))
// Map both sides (bimap)
let bimapped = left.map_either(x => x * 2, s => s + " world")
assert_true(bimapped is Left(20))
}///|
test "type conversions" {
// From Option
let some_val : Int? = Some(42)
let none_val : Int? = None
let either_from_some = from_option_left_or(some_val, "default")
assert_true(either_from_some is Left(42))
let either_from_none = from_option_left_or(none_val, "default")
assert_true(either_from_none is Right("default"))
// From Result
let ok_result : Result[String, Int] = Ok("success")
let err_result : Result[String, Int] = Err(404)
let either_ok = from_result(ok_result)
assert_true(either_ok is Right("success"))
let either_err = from_result(err_result)
assert_true(either_err is Left(404))
// To Result
let left_either : Either[Int, String] = Left(404)
let result_from_either = left_either.to_result()
assert_true(result_from_either is Err(404))
}///|
test "utility operations" {
let left : Either[Int, String] = Left(42)
let right : Either[Int, String] = Right("hello")
// Flip Left and Right
assert_true(left.flip() is Right(42))
assert_true(right.flip() is Left("hello"))
// Expect operations (abort on wrong variant)
assert_eq(left.expect_left("Expected left"), 42)
assert_eq(right.expect_right("Expected right"), "hello")
// Or else operations with lazy evaluation
let computed_left = right.left_or_else(() => 100)
assert_eq(computed_left, 100)
let computed_right = left.right_or_else(() => "computed")
assert_eq(computed_right, "computed")
}///|
test "advanced usage" {
// Chain operations
let result = Left(5)
|> Either::map_left(x => x * 2) // Left(10)
|> Either::map_right(x => x + 1) // Still Left(10)
|> Either::flip() // Right(10)
|> Either::map_right(x => x + 5) // Right(15)
assert_true(result is Right(15))
// Combining with control flow
let values : Array[Either[Int, String]] = [Left(1), Right("two"), Left(3)]
let lefts = []
let rights = []
for either in values {
match either {
Either::Left(x) => lefts.push(x)
Either::Right(s) => rights.push(s)
}
}
assert_eq(lefts, [1, 3])
assert_eq(rights, ["two"])
}///|
test "creating either values" {
// 创建 Left 和 Right 值
let left_val : Either[Int, String] = left(42)
let right_val : Either[Int, String] = right("hello")
// 直接使用构造函数
let left_direct : Either[Int, Unit] = Left(42)
let right_direct : Either[Unit, String] = Right("hello")
assert_true(left_val is Left(42))
assert_true(right_val is Right("hello"))
assert_true(left_direct is Left(42))
assert_true(right_direct is Right("hello"))
}///|
test "checking variants" {
let values : Array[Either[Int, String]] = [Left(1), Right("two"), Left(3)]
// 使用 is_left() 和 is_right()
assert_true(values[0].is_left())
assert_true(values[1].is_right())
assert_false(values[2].is_right())
// 使用 `is` 进行模式匹配 (首选)
assert_true(values[0] is Left(_))
assert_true(values[1] is Right(_))
assert_false(values[2] is Right(_))
}///|
test "extracting values" {
let left_val : Either[Int, String] = Either::Left(42)
let right_val : Either[Int, String] = Either::Right("hello")
// 提取为 Option
assert_true(left_val.left() is Some(42))
assert_true(left_val.right() is None)
assert_true(right_val.right() is Some("hello"))
assert_true(right_val.left() is None)
// 使用默认值提取
assert_eq(left_val.left_or(0), 42)
assert_eq(left_val.right_or("default"), "default")
assert_eq(right_val.left_or(0), 0)
assert_eq(right_val.right_or("default"), "hello")
}///|
test "mapping operations" {
let left : Either[Int, String] = Left(10)
let right : Either[Int, String] = Right("hello")
// 只映射 left
let mapped_left = left.map_left(x => x * 2)
assert_true(mapped_left is Left(20))
// 只映射 right
let mapped_right = right.map_right(s => s + " world")
assert_true(mapped_right is Right("hello world"))
// 映射两边 (bimap)
let bimapped = left.map_either(x => x * 2, s => s + " world")
assert_true(bimapped is Left(20))
}///|
test "type conversions" {
// 从 Option
let some_val : Int? = Some(42)
let none_val : Int? = None
let either_from_some = from_option_left_or(some_val, "default")
assert_true(either_from_some is Left(42))
let either_from_none = from_option_left_or(none_val, "default")
assert_true(either_from_none is Right("default"))
// 从 Result
let ok_result : Result[String, Int] = Ok("success")
let err_result : Result[String, Int] = Err(404)
let either_ok = from_result(ok_result)
assert_true(either_ok is Right("success"))
let either_err = from_result(err_result)
assert_true(either_err is Left(404))
// 转换为 Result
let left_either : Either[Int, String] = Left(404)
let result_from_either = left_either.to_result()
assert_true(result_from_either is Err(404))
}///|
test "utility operations" {
let left : Either[Int, String] = Left(42)
let right : Either[Int, String] = Right("hello")
// 翻转 Left 和 Right
assert_true(left.flip() is Right(42))
assert_true(right.flip() is Left("hello"))
// Expect 操作 (在错误的变体上会中止)
assert_eq(left.expect_left("Expected left"), 42)
assert_eq(right.expect_right("Expected right"), "hello")
// 使用惰性求值的 or_else 操作
let computed_left = right.left_or_else(() => 100)
assert_eq(computed_left, 100)
let computed_right = left.right_or_else(() => "computed")
assert_eq(computed_right, "computed")
}///|
test "advanced usage" {
// 链式操作
let result = Left(5)
|> Either::map_left(x => x * 2) // Left(10)
|> Either::map_right(x => x + 1) // 仍然是 Left(10)
|> Either::flip() // Right(10)
|> Either::map_right(x => x + 5) // Right(15)
assert_true(result is Right(15))
// 与控制流结合
let values : Array[Either[Int, String]] = [Left(1), Right("two"), Left(3)]
let lefts = []
let rights = []
for either in values {
match either {
Either::Left(x) => lefts.push(x)
Either::Right(s) => rights.push(s)
}
}
assert_eq(lefts, [1, 3])
assert_eq(rights, ["two"])
}test {
let left : Either[Int, String] = Left(42)
let result1 = left.either(x => x * 2, s => s.length())
assert_eq(result1, 84)
let right : Either[Int, String] = Right("hello")
let result2 = right.either(x => x * 2, s => s.length())
assert_eq(result2, 5)
}test {
let left_value : Either[Int, String] = Left(42)
let unwrapped = left_value.expect_left("Expected left value")
assert_eq(unwrapped, 42)
}test {
let right_value : Either[Int, String] = Right("hello")
let unwrapped = right_value.expect_right("Expected right value")
assert_eq(unwrapped, "hello")
}test {
let left_ok : Either[Result[Int, String], Result[Bool, String]] = Left(Ok(42))
let result1 = left_ok.factor_err()
assert_true(result1 is Ok(Left(42)))
let left_err : Either[Result[Int, String], Result[Bool, String]] = Left(
Err("error"),
)
let result2 = left_err.factor_err()
assert_true(result2 is Err("error"))
let right_ok : Either[Result[Int, String], Result[Bool, String]] = Right(
Ok(true),
)
let result3 = right_ok.factor_err()
assert_true(result3 is Ok(Right(true)))
}test {
let left_pair : Either[(Int, String), (Int, Bool)] = Left((42, "hello"))
let result1 = left_pair.factor_first()
assert_eq(result1.0, 42)
assert_true(result1.1 is Left("hello"))
let right_pair : Either[(Int, String), (Int, Bool)] = Right((42, true))
let result2 = right_pair.factor_first()
assert_eq(result2.0, 42)
assert_true(result2.1 is Right(true))
}test {
let left_some : Either[Int?, String?] = Left(Some(42))
let result1 = left_some.factor_none()
assert_true(result1 is Some(Left(42)))
let left_none : Either[Int?, String?] = Left(None)
let result2 = left_none.factor_none()
assert_true(result2 is None)
let right_some : Either[Int?, String?] = Right(Some("hello"))
let result3 = right_some.factor_none()
assert_true(result3 is Some(Right("hello")))
}test {
let left_ok : Either[Result[Int, String], Result[Int, Bool]] = Left(Ok(42))
let result1 = left_ok.factor_ok()
assert_true(result1 is Ok(42))
let left_err : Either[Result[Int, String], Result[Int, Bool]] = Left(
Err("error"),
)
let result2 = left_err.factor_ok()
assert_true(result2 is Err(Left("error")))
let right_err : Either[Result[Int, String], Result[Int, Bool]] = Right(
Err(false),
)
let result3 = right_err.factor_ok()
assert_true(result3 is Err(Right(false)))
}test {
let left_pair : Either[(String, Int), (Bool, Int)] = Left(("hello", 42))
let result1 = left_pair.factor_second()
assert_true(result1.0 is Left("hello"))
assert_eq(result1.1, 42)
let right_pair : Either[(String, Int), (Bool, Int)] = Right((true, 42))
let result2 = right_pair.factor_second()
assert_true(result2.0 is Right(true))
assert_eq(result2.1, 42)
}test {
let left : Either[Int, Unit] = Left(123)
assert_true(left.flip() is Right(123))
let right : Either[Unit, String] = Right("hello")
assert_true(right.flip() is Left("hello"))
}test {
let values : Array[Either[Int, String]] = [Left(1), Right("two"), Left(3)]
assert_true(values[0].is_left())
assert_false(values[1].is_left())
assert_true(values[2].is_left())
// Note: use `is` may be better.
assert_true(values[0] is Left(_))
assert_false(values[1] is Left(_))
assert_true(values[2] is Left(_))
}test {
let values : Array[Either[Int, String]] = [Left(1), Right("two"), Left(3)]
assert_false(values[0].is_right())
assert_true(values[1].is_right())
assert_false(values[2].is_right())
// Note: use `is` may be better.
assert_false(values[0] is Right(_))
assert_true(values[1] is Right(_))
assert_false(values[2] is Right(_))
}test {
let values : Array[Either[Int, String]] = [Left(1), Right("two"), Left(3)]
assert_true(values[0].left() is Some(_))
assert_true(values[1].left() is None)
assert_true(values[2].left() is Some(_))
}test {
let left : Either[Int, String] = Left(5)
let result = left.left_and_then(x => {
if x > 0 {
Left(x * 2)
} else {
Right("negative")
}
})
assert_true(result is Left(10))
let right : Either[Int, String] = Right("hello")
let result = right.left_and_then(x => Left(x * 2))
assert_true(result is Right("hello"))
}test {
let left_value : Either[Int, String] = Left(42)
assert_eq(left_value.left_or(0), 42)
let right_value : Either[Int, String] = Right("hello")
assert_eq(right_value.left_or(0), 0)
}test {
let left_value : Either[Int, String] = Left(42)
assert_eq(left_value.left_or_else(() => 0), 42)
let right_value : Either[Int, String] = Right("hello")
assert_eq(right_value.left_or_else(() => 100), 100)
}test {
let left_value : Either[Int, String] = Left(42)
let unwrapped = left_value.left_unwrap()
assert_eq(unwrapped, 42)
}test {
let left : Either[Int, Int] = Left(5)
let new_left = left.map(x => x * 2)
assert_true(new_left is Left(10))
let right : Either[Int, Int] = Right(5)
let new_right = right.map(x => x * 2)
assert_true(new_right is Right(10))
}test {
let left : Either[Int, String] = Left(123)
let new_left = left.map_either(x => x + 1, s => s + " world")
assert_true(new_left is Left(124))
let right : Either[Int, String] = Right("hello")
let new_right = right.map_either(x => x + 1, s => s + " world")
assert_true(new_right is Right("hello world"))
}test {
let left : Either[Int, Unit] = Left(123)
let new_left = left.map_left(x => x + 1)
assert_true(new_left is Left(124))
let right : Either[Int, String] = Right("hello")
let new_right = right.map_left(x => x + 1)
assert_true(new_right is Right("hello"))
}test {
let left : Either[Int, String] = Left(123)
let new_left = left.map_right(x => x + " world")
assert_true(new_left is Left(123))
let right : Either[Unit, String] = Right("hello")
let new_right = right.map_right(x => x + " world")
assert_true(new_right is Right("hello world"))
}test {
let values : Array[Either[Int, String]] = [Left(1), Right("two"), Left(3)]
assert_true(values[0].right() is None)
assert_true(values[1].right() is Some(_))
assert_true(values[2].right() is None)
}test {
let right : Either[String, Int] = Right(5)
let result = right.right_and_then(x => {
if x > 0 {
Right(x * 2)
} else {
Left("negative")
}
})
assert_true(result is Right(10))
let left : Either[String, Int] = Left("error")
let result2 = left.right_and_then(x => Right(x * 2))
assert_true(result2 is Left("error"))
}test {
let right_value : Either[Int, String] = Right("hello")
assert_eq(right_value.right_or("default"), "hello")
let left_value : Either[Int, String] = Left(42)
assert_eq(left_value.right_or("default"), "default")
}test {
let right_value : Either[Int, String] = Right("hello")
assert_eq(right_value.right_or_else(() => "default"), "hello")
let left_value : Either[Int, String] = Left(42)
assert_eq(left_value.right_or_else(() => "computed"), "computed")
}test {
let right_value : Either[Int, String] = Right("hello")
let unwrapped = right_value.right_unwrap()
assert_eq(unwrapped, "hello")
}test {
let right_value : Either[String, Int] = Right(42)
let result_ok = right_value.to_result()
assert_true(result_ok is Ok(42))
let left_value : Either[String, Int] = Left("error")
let result_err = left_value.to_result()
assert_true(result_err is Err("error"))
}test {
let eithers : Array[Either[Int, String]] = [
Left(1),
Right("a"),
Left(2),
Right("b"),
Left(3),
]
let lefts = collect_lefts(eithers)
assert_eq(lefts, [1, 2, 3])
let all_rights : Array[Either[Int, String]] = [Right("a"), Right("b")]
let no_lefts = collect_lefts(all_rights)
assert_eq(no_lefts, [])
}test {
let eithers : Array[Either[Int, String]] = [
Left(1),
Right("a"),
Left(2),
Right("b"),
Left(3),
]
let rights = collect_rights(eithers)
assert_eq(rights, ["a", "b"])
let all_lefts : Array[Either[Int, String]] = [Left(1), Left(2)]
let no_rights = collect_rights(all_lefts)
assert_eq(no_rights, [])
}test {
let some_value : Int? = Some(42)
let result : Either[Int, Unit] = from_option_left(some_value)
assert_true(result is Left(42))
}test {
let some_value : Int? = Some(42)
let result = from_option_left_or(some_value, "default")
assert_true(result is Left(42))
let none_value : Int? = None
let result2 = from_option_left_or(none_value, "default")
assert_true(result2 is Right("default"))
}test {
let some_value : Int? = Some(42)
let result = from_option_left_or_else(some_value, () => "computed")
assert_true(result is Left(42))
let none_value : Int? = None
let result2 = from_option_left_or_else(none_value, () => "computed")
assert_true(result2 is Right("computed"))
}test {
let some_value : String? = Some("hello")
let result : Either[Unit, String] = from_option_right(some_value)
assert_true(result is Right("hello"))
}test {
let some_value : String? = Some("hello")
let result = from_option_right_or(some_value, 42)
assert_true(result is Right("hello"))
let none_value : String? = None
let result2 = from_option_right_or(none_value, 42)
assert_true(result2 is Left(42))
}test {
let some_value : String? = Some("hello")
let result = from_option_right_or_else(some_value, () => 42)
assert_true(result is Right("hello"))
let none_value : String? = None
let result2 = from_option_right_or_else(none_value, () => 42)
assert_true(result2 is Left(42))
}test {
let ok_result : Result[String, Int] = Ok("success")
let either_ok = from_result(ok_result)
assert_true(either_ok is Right("success"))
let err_result : Result[String, Int] = Err(404)
let either_err = from_result(err_result)
assert_true(either_err is Left(404))
}test {
let left : Either[Int, String] = left(123)
assert_true(left is Left(123))
}test {
let eithers : Array[Either[Int, String]] = [
Left(1),
Right("a"),
Left(2),
Right("b"),
Left(3),
]
let (lefts, rights) = partition(eithers)
assert_eq(lefts, [1, 2, 3])
assert_eq(rights, ["a", "b"])
}A MoonBit library providing the Either type for representing values with two possible types, inspired by Rust's either and Haskell's either libraries.