structure Shape = struct
datatype shape =
Circle of real
| Rectangle of real * real
| Point
end
structure Bound = struct
datatype shape =
Circle of real
| Rectangle of real * real
end
This is doing things quick and dirty. For this trivial example it's fine, and I think a good example of why making sum-types low friction is a good idea. It completely changes how you solve problems when they're fire and forget like this. signature SHAPE_TYPE = sig
datatype shape =
Circle of real
| Rectangle of real * real
| Point
val Circle : real -> shape
val Rectangle : real * real -> shape
val Point : shape
end
functor FullShape () : SHAPE_TYPE = struct
datatype shape =
Circle of real
| Rectangle of real * real
| Point
val Circle = Circle
val Rectangle = Rectangle
val Point = Point
end
functor RemovePoint (S : SHAPE_TYPE) :> sig
type shape
val Circle : real -> shape
val Rectangle : real * real -> shape
end = struct
type shape = S.shape
val Circle = S.Circle
val Rectangle = S.Rectangle
end
structure Shape = FullShape()
structure Bound = RemovePoint(Shape)
This is extremely overkill for the example, but it also demonstrates a power you're not getting out of C# or Java without usage of reflection. This is closer to the system of inheritance, but it's a bit better designed. The added benefit here over reflection is that the same principle of "invalid program states are unrepresentable" applies here as well, because it's the exact same system being used. You'll also note that even though it's a fair bit closer conceptually to classes, the sum-type is still distinct. DoesNotReturnPoint : Shape.shape -> Bound.shape
Haskell has actual GADTs and proper higher kinded polymorphism, and a few other features where this all looks very different and much terser. Newer languages bake subtyping into the grammar. datatype shape =
Circle of real
| Rectangle of real * real
| Point
Circle : real -> shape
Rectangle : real * real -> shape
Point : () -> shape
A case itself isn't a type, though it has a type. Thanks to pattern matching, you're already unwrapping the parameter to the type-constructor when handling the case of a sum-type. It's all about declaration locality. (real * real) doesn't depend on the existence of shape. public abstract record Shape;
public sealed record Circle(double Radius) : Shape;
public sealed record Rectangle(double Width, double Height) : Shape;
public sealed record Point() : Shape;
double Area(Shape shape) => shape switch
{
Circle c => Math.PI * c.Radius * c.Radius,
Rectangle r => r.Width * r.Height,
Point => 0.0,
_ => throw new ArgumentException("Unknown shape", nameof(shape))
};
ML: datatype shape =
Circle of real
| Rectangle of real * real
| Point
val result =
case shape of
Circle r => Math.pi * r * r
| Rectangle (w, h) => w * h
| Point => 0.0
They're pretty much the same outside of C#'s OOP quirkiness getting in it's own way.
Substantiate this.
> weird name choice but whatever
I don't think this kind of snarky potshot is in line with the commentary guidelines. Perhaps you could benefit from a refresher?
https://news.ycombinator.com/newsguidelines.html#comments
> Thanks to subtyping, no contortion needed
I see the same degree of contortion, actually. Far more noisy, at that.
> No need to use 7 more lines to create a separate, unrelated type.
You're still creating a type, because you understand that a sum-type with a different set of cases is fundamentally a different type. Just like a class with a different set of inheritance is a different type. And while it's very cute to compress it all into a single line, it's really not compelling in the context of readability and "write once, use many". Which is the point you were making, although it was on an entirely different part of the grammar.
> Great analogy, except for the fact that someone from the Java team explicitly said they're drawing inspirations from ML.
ML didn't invent ADTs, and I think you know it's more than disingenuous to imply the quotation means that the type-system in Java which hasn't undergone any fundamental changes in the history of the language (nor could it without drastically changing the grammar of the language and breaking the close relationship to the JVM) was lifted from ML.