Why do We Need Sum Types?

前端 未结 4 586
广开言路
广开言路 2021-02-08 05:09

Imagine a language which doesn\'t allow multiple value constructors for a data type. Instead of writing

data Color = White | Black | Blue

we wo

4条回答
  •  清歌不尽
    2021-02-08 05:35

    Haskell's sum type is very similar to your :|:.

    The difference between the two is that the Haskell sum type | is a tagged union, while your "sum type" :|: is untagged.

    Tagged means every instance is unique - you can distunguish Int | Int from Int (actually, this holds for any a):

    data EitherIntInt = Left Int | Right Int
    

    In this case: Either Int Int carries more information than Int because there can be a Left and Right Int.

    In your :|:, you cannot distinguish those two:

    type EitherIntInt = Int :|: Int
    

    How do you know if it was a left or right Int?

    See the comments for an extended discussion of the section below.

    Tagged unions have another advantage: The compiler can verify whether you as the programmer handled all cases, which is implementation-dependent for general untagged unions. Did you handle all cases in Int :|: Int? Either this is isomorphic to Int by definition or the compiler has to decide which Int (left or right) to choose, which is impossible if they are indistinguishable.

    Consider another example:

    type (Integral a, Num b) => IntegralOrNum a b = a :|: b    -- untagged
    data (Integral a, Num b) => IntegralOrNum a b = Either a b -- tagged
    

    What is 5 :: IntegralOrNum Int Double in the untagged union? It is both an instance of Integral and Num, so we can't decide for sure and have to rely on implementation details. On the other hand, the tagged union knows exactly what 5 should be because it is branded with either Left or Right.


    As for naming: The disjoint union in Haskell is a union type. ADTs are only a means of implementing these.

提交回复
热议问题