Scala中的Option[T]是从哪里来的?

9

我在Scala开发方面还是个新手,但我发现Option[T]概念非常棒,特别是在使用Some和None与模式匹配时。目前我甚至在一个C#项目中进行了一定程度的实现,但由于没有模式匹配,所以并不太棒。

真正的问题是,这个对象背后的理论是什么?它是Scala专有的东西吗?函数式语言?我应该在哪里找到更多相关知识呢?


2
公平地说,对于大多数Option的强大功能,您并不需要模式匹配。您只需要声明点协变性、底部类型、lambda和惰性求值。使用map+getOrElse代替模式匹配。 - oxbow_lakes
确实。我在C#中经常使用Option,它很适合LINQ。 - Jesper Nordenberg
@oxbow_lakes:那些东西与Option的强大有什么关系?或许是lambda,可以与map一起使用,但_|_和惰性又与之有何关联? - Dan Burton
3个回答

13

我一直认为这个概念来自Haskell,并且有一个名为 Maybe monad 的名称。

但是在进行了一些调查后,我发现SML论文中提到了一些关于选项类型的参考资料,正如@ShiDoiSi所说。此外,它具有与Scala相同的语义(Some/None)。 我能找到的最古老的论文是这篇 (约在89年左右)(请见第6页上的脚注)。


8
您不需要使用模式匹配来使用Option。下面是我用C#为您编写的代码示例。请注意,Fold函数会处理本应进行模式匹配的任何内容。
通常建议使用高级组合器而不是模式匹配。例如,如果您的特定函数可以使用Select编写,则应使用它而不是Fold(它相当于模式匹配)。否则,假设代码没有副作用(因此可以进行等式推理),您实际上将重新实现现有代码。这适用于所有语言,而不仅仅是Scala或C#。
using System;
using System.Collections;
using System.Collections.Generic;

namespace Example {
  /// <summary>
  /// An immutable list with a maximum length of 1.
  /// </summary>
  /// <typeparam name="A">The element type held by this homogenous structure.</typeparam>
  /// <remarks>This data type is also used in place of a nullable type.</remarks>
  public struct Option<A> : IEnumerable<A> {
    private readonly bool e;
    private readonly A a;

    private Option(bool e, A a) {
      this.e = e;
      this.a = a;
    }

    public bool IsEmpty {
      get {
        return e;
      }
    }

    public bool IsNotEmpty{
      get {
        return !e;
      }
    }

    public X Fold<X>(Func<A, X> some, Func<X> empty) {
      return IsEmpty ? empty() : some(a);
    }

    public void ForEach(Action<A> a) {
      foreach(A x in this) {
        a(x);
      }
    }

    public Option<A> Where(Func<A, bool> p) {
      var t = this;
      return Fold(a => p(a) ? t : Empty, () => Empty);
    }

    public A ValueOr(Func<A> or) {
      return IsEmpty ? or() : a;
    }

    public Option<A> OrElse(Func<Option<A>> o) {
      return IsEmpty ? o() : this;
    }

    public bool All(Func<A, bool> f) {
      return IsEmpty || f(a);
    }

    public bool Any(Func<A, bool> f) {
      return !IsEmpty && f(a);
    }

    private A Value {
      get {
        if(e)
          throw new Exception("Value on empty Option");
        else
          return a;
      }
    }

    private class OptionEnumerator : IEnumerator<A> {
      private bool z = true;
      private readonly Option<A> o;
      private Option<A> a;

      internal OptionEnumerator(Option<A> o) {
        this.o = o;
      }

      public void Dispose() {}

      public void Reset() {
        z = true;
      }

      public bool MoveNext() {
        if(z) {
          a = o;
          z = false;
        } else
          a = Option<A>.Empty;

        return !a.IsEmpty;
      }

      A IEnumerator<A>.Current {
        get {
          return o.Value;
        }
      }

      public object Current {
        get {
          return o.Value;
        }
      }
    }

    private OptionEnumerator Enumerate() {
      return new OptionEnumerator(this);
    }

    IEnumerator<A> IEnumerable<A>.GetEnumerator() {
      return Enumerate();
    }

    IEnumerator IEnumerable.GetEnumerator() {
      return Enumerate();
    }

    public static Option<A> Empty {
      get {
        return new Option<A>(true, default(A));
      }
    }

    public static Option<A> Some(A t) {
      return new Option<A>(false, t);
    }
  }
}

“通常不鼓励使用模式匹配,而是倾向于使用更高级别的组合器” - 我发现这在Scala社区中通常是正确的,尽管个人强烈不同意这种观点。 - Dan Burton
1
这不是一个有争议的声明。 - Tony Morris
5
当托尼·莫里斯说某些话不具有争议性时,这意味着某些事情(虽然不一定是他实际说的) 。 - Dave Griffith
看到你一如既往地提供洞察力和实用性。 - Tony Morris

7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接