Skip to content

Instantly share code, notes, and snippets.

@RimuruDev
Forked from adammyhre/Either.cs
Created December 11, 2024 09:37
Show Gist options
  • Select an option

  • Save RimuruDev/40ab4cba3509f50992b36178a5f1e3fd to your computer and use it in GitHub Desktop.

Select an option

Save RimuruDev/40ab4cba3509f50992b36178a5f1e3fd to your computer and use it in GitHub Desktop.

Revisions

  1. @adammyhre adammyhre created this gist Dec 1, 2024.
    51 changes: 51 additions & 0 deletions Either.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,51 @@
    using System;
    using System.Collections.Generic;

    public struct Either<TLeft, TRight> {
    readonly TLeft left;
    readonly TRight right;
    readonly bool isRight;

    Either(TLeft left, TRight right, bool isRight) {
    this.left = left;
    this.right = right;
    this.isRight = isRight;
    }

    public bool IsLeft => !isRight;
    public bool IsRight => isRight;

    public TLeft Left {
    get {
    if (IsRight) throw new InvalidOperationException("No Left value present.");
    return left;
    }
    }

    public TRight Right {
    get {
    if (IsLeft) throw new InvalidOperationException("No Right value present.");
    return right;
    }
    }

    public static Either<TLeft, TRight> FromLeft(TLeft left) => new (left, default, false);
    public static Either<TLeft, TRight> FromRight(TRight right) => new (default, right, true);

    public TResult Match<TResult>(Func<TLeft, TResult> leftFunc, Func<TRight, TResult> rightFunc) {
    return IsRight ? rightFunc(right) : leftFunc(left);
    }

    public Either<TLeft, TResult> Select<TResult>(Func<TRight, TResult> map) {
    return IsRight ? Either<TLeft, TResult>.FromRight(map(right)) : Either<TLeft, TResult>.FromLeft(left);
    }

    public Either<TLeft, TResult> SelectMany<TResult>(Func<TRight, Either<TLeft, TResult>> bind) {
    return IsRight ? bind(right) : Either<TLeft, TResult>.FromLeft(left);
    }

    public static implicit operator Either<TLeft, TRight>(TLeft left) => FromLeft(left);
    public static implicit operator Either<TLeft, TRight>(TRight right) => FromRight(right);

    public override string ToString() => IsRight ? $"Right({right})" : $"Left({left})";
    }
    56 changes: 56 additions & 0 deletions Optional.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,56 @@
    using System;
    using System.Collections.Generic;

    public struct Optional<T> {
    public static readonly Optional<T> NoValue = new Optional<T>();

    readonly bool hasValue;
    readonly T value;

    public Optional(T value) {
    this.value = value;
    hasValue = true;
    }

    public T Value => hasValue ? value : throw new InvalidOperationException("No value");
    public bool HasValue => hasValue;

    public T GetValueOrDefault() => value;
    public T GetValueOrDefault(T defaultValue) => hasValue ? value : defaultValue;

    public TResult Match<TResult>(Func<T, TResult> onValue, Func<TResult> onNoValue) {
    return hasValue ? onValue(value) : onNoValue();
    }

    public Optional<TResult> SelectMany<TResult>(Func<T, Optional<TResult>> bind) {
    return hasValue ? bind(value) : Optional<TResult>.NoValue;
    }

    public Optional<TResult> Select<TResult>(Func<T, TResult> map) {
    return hasValue ? new Optional<TResult>(map(value)) : Optional<TResult>.NoValue;
    }

    public static Optional<TResult> Combine<T1, T2, TResult>(Optional<T1> first, Optional<T2> second, Func<T1, T2, TResult> combiner) {
    if (first.HasValue && second.HasValue) {
    return new Optional<TResult>(combiner(first.Value, second.Value));
    }

    return Optional<TResult>.NoValue;
    }

    public static Optional<T> Some(T value) => new Optional<T>(value);
    public static Optional<T> None() => NoValue;

    public override bool Equals(object obj) => obj is Optional<T> other && Equals(other);
    public bool Equals(Optional<T> other) => !hasValue ? !other.hasValue : EqualityComparer<T>.Default.Equals(value, other.value);

    public override int GetHashCode() => (hasValue.GetHashCode() * 397) ^ EqualityComparer<T>.Default.GetHashCode(value);

    public override string ToString() => hasValue ? $"Some({value})" : "None";

    public static implicit operator Optional<T>(T value) => new Optional<T>(value);

    public static implicit operator bool(Optional<T> value) => value.hasValue;

    public static explicit operator T(Optional<T> value) => value.Value;
    }