Discriminated Unions
bearophile
bearophileHUGS at lycos.com
Mon Nov 18 16:40:07 PST 2013
Stretto:
> F# now has Discriminated Unions:
>
> http://msdn.microsoft.com/en-US/library/dd233226.aspx
>
> Would it be possible to have something similar in D?
Unless I am missing something, they seem the regular algebraic
types you find in Haskell, etc.
A little example program in Haskell (from
https://github.com/Dobiasd/articles/blob/master/from_oop_to_fp_-_inheritance_and_the_expression_problem.md
):
import Data.List
data Base = Foo Int | Bar String
step :: Base -> Int -> Base
-- Add delta to internal state.
step (Foo intVal) delta = Foo $ intVal + delta
-- Concat delta as string to internal state.
step (Bar strVal) delta = Bar $ strVal ++ show delta
display :: Base -> String
display (Foo intVal) = show intVal
display (Bar strVal) = strVal
-- Steps every object in l by 1.
stepAll :: [Base] -> [Base]
stepAll l = map (\b -> step b 1) l
-- Displays all objects in l beneath each other.
displayAll :: [Base] -> IO ()
displayAll l = putStrLn $ concat (intersperse "\n" $ map display
l)
main =
let
-- Fill a list with "derived instances".
l :: [Base]
l = [Foo 0, Bar ""]
-- Step every object two times.
l' = (stepAll . stepAll) l
in
-- Show result.
displayAll l'
In D with OOP:
import std.stdio, std.conv, std.algorithm;
interface Base {
void step(in int delta) pure;
string display() const pure;
}
class Foo: Base {
this(in int i) pure nothrow { this.intVal = i; }
/// Add delta to internal state.
override void step(in int delta) pure nothrow { intVal +=
delta; }
override string display() const pure { return intVal.text; }
private int intVal;
}
class Bar: Base {
this(in string s) pure nothrow { this.strVal = s; }
/// Concat delta as string to internal state.
override void step(in int delta) pure { strVal ~= delta.text;
}
override string display() const pure nothrow { return strVal;
}
private string strVal;
}
alias BaseArr = Base[];
/// Steps every object in items by 1.
void stepAll(BaseArr items) pure {
foreach (o; items)
o.step(1);
}
/// Displays all objects in items beneath each other.
void displayAll(in BaseArr items) {
writefln("%-(%s\n%)", items.map!(o => o.display));
}
void main() {
// Fill a vector with base class pointers to derived
instances.
//BaseArr l = [new Foo(0), new Bar("")];
BaseArr l = [new Foo(0)];
l ~= new Bar("");
// Step every object two times.
l.stepAll;
l.stepAll;
// Show result.
l.displayAll;
}
In D immutable:
import std.stdio, std.algorithm, std.variant, std.conv, std.array;
alias Base = Algebraic!(int, string);
Base step(in Base b, in int delta) {
if (auto bi = b.peek!int)
return Base(*bi + delta); // Add delta to internal state.
else if (auto bs = b.peek!string)
return Base(*bs ~ delta.text); // Concat delta as string
to internal state.
assert(0);
}
string display(in Base b) {
if (auto bi = b.peek!int)
return text(*bi);
else if (auto bs = b.peek!string)
return *bs;
assert(0);
}
// Steps every object in l by 1.
Base[] stepAll(in Base[] l) { return l.map!(b =>
b.step(1)).array; }
// Displays all objects in l beneath each other.
void displayAll(in Base[] l) { writefln("%-(%s\n%)",
l.map!display); }
void main() {
// Fill a list with "derived instances".
immutable l = [Base(0), Base("")];
// Step every object two times.
const l2 = l.stepAll.stepAll;
// Show result.
l2.displayAll;
}
How it could become with some improvements in Algebraic (it
defines an enum of the types, usable in a final switch):
import std.stdio, std.algorithm, std.variant, std.conv, std.array;
alias Base = Algebraic!(int, string);
Base step(in Base b, in int delta) {
final switch (b.type) with (b) {
case intType: return Base(b.get!int + delta);
case stringType: return Base(b.get!string ~ delta.text);
}
}
string display(in Base b) {
final switch (b.type) with (b) {
case intType: return b.get!int.text;
case stringType: return b.get!string;
}
}
// Steps every object in l by 1.
Base[] stepAll(in Base[] l) { return l.map!(b =>
b.step(1)).array; }
// Displays all objects in l beneath each other.
void displayAll(in Base[] l) { writefln("%-(%s\n%)",
l.map!display); }
void main() {
// Fill a list with "derived instances".
immutable l = [Base(0), Base("")];
// Step every object two times.
const l2 = l.stepAll.stepAll;
// Show result.
l2.displayAll;
}
This is much worse than the code you can write in Rust, but
perhaps it's still usable.
Bye,
bearophile
More information about the Digitalmars-d
mailing list