NAME

Data::Variant -- Variant datatypes for perl.

SYNOPSIS

    use Data::Variant;
    use vars qw(&Empty &Leaf &Node);

    register_variant("Tree","Empty","Leaf <NUM>","Node Tree Tree");
    my $tree = Node((Node ((Leaf 3), (Leaf 4))), Leaf 5);

    sub printTree {
	my $tree = shift;
	my ($data, $left, $right);

	print "Data $data\n" 
	    if (match $tree,"Leaf", $data);
	printTree($left), printTree($right) 
	    if (match $tree,"Node",$left,$right);
    }

DESCRIPTION

This module offers a Haskell/O'Caml-style for variant data types. You can register data types and then both construct them using the constructors give, and match against them as conditionals. The best way to understand what the module does is probably to look at the included examples. Pattern matching together with variants is (in the author's opinion) one of the very most useful features in Haskell and while this implementation is very informal it serves the same practical purpose.

There is some (very limited) typechecking available to make sure that you use your data structure as intended (well, as declared really but if you are wise these two coincide).

For the programmer unused to pattern matching, looking at the synoposis or the examples is probably the easiest way to get an idea of how to use the module.

FUNCTIONS

register_variant(NAME [, CONSTRUCTORS])

This function registers a variant with the module. The NAME should be a string uniquely naming the variant.

Next should come a list of constructors. A constructor can come in one of two forms:

  • A list reference

    The first element of the list should be a string, containing the name of the constructor. This name will be the name of the constructor function that will be used to construct new instances of this variant. By convention constructors start with a capital letter.

    The other elements should be strings indicating the type of the variable stored in this position.

    We are allowed the following types in this version:

    • <NUM> - Numbers

    • <STRING> - Strings

    • <REF> - References

    • * - wildcard, allow any type for this field

    • Type - allow only other variants of Type.

    This information is later used for some basic typechecking, see "Typechecking".

  • A single string

    The string should just be a space separated list, basically containing the same as if it was list reference instead.

NOTE: The constructor has to be globally unique within your program.

Examples:

# Registers the variant Tree with the constructors:
#  Empty, Leaf and Node.
#  The Empty node carries no data, the leaf node carries an int
#  and an internal node carries two subtrees.
register_variant("Tree","Empty","Leaf <NUM>","Node Tree Tree");

# Essentially the same, but using list reference form.
register_variant("Tree2", ["Empty2"],["Leaf2","<NUM>"],["Node2", "Tree2","Tree2"]);

# The Maybe type from Haskell, often called an "optional value".
register_variant("Maybe", "Nothing", "Just *");
export_variant(VARIANT)
$val->export_variant

As a function, this function exports the variant named by the argument VARIANT to the calling module, making the constructors available in the module.

As a method call, on an object that is a variant value, it exports the constructors for the variant that the object is an instance of.

Constructor([VARLIST])

The constructors that you gave register_variant will be exported as functions to the calling package, and are used to create new instances of the variant. It is during this instantiation phase that type checking is performed.

Note that if you want to use the functions without paranteses, or if you have warnings turned on (and you probably should) you will have to predeclare your constructors somehow, either by use vars qw{&Cons} or by sub Cons.

Note: The constructor will return an object with the appropriate data.

Examples:

# Creation of some simple trees
my $left  = Node ((Leaf 1), (Leaf 4));
my $right = Node ((Leaf 3), Empty);
my $tree  = Node $left, $right;

# A few maybe variants
my $nth   = Nothing
my $sth   = Just "A string";
match([OBJ], CONS, [VARLIST])
$obj->match(CONS,[VARLIST]
match(OBJ)

In its first two forms match checks is OBJ is constructed using the constructor CONS given. If it matches the variables in VARLIST are filled with the values of the fields of the object.

The number of elements in VARLIST must match the number of values in the object.

The first argument OBJ can be left out if it has been pre-set using set_match.

It its second form, with only an object as parameter, it returns a function reference that is useful in a switch statement. The contents of each case must then be created using mkpat.

mkpat(CONS, [VARLIST])

This creates a reference to an array containing what would normally be the input to match. This is mainly useful when working with switch statements.

set_match(OBJ)
$object->set_match

Presets an object to match against so that the first parameter of match can be left out in subsequent calls.

DETAILS

Typechecking

The typechecking is quite rudimentary. At runtime the type of the value inserted is checked so that it corresponds to the type given in the declaration. Currently using a bad type will make the library croak, complaining about the type.

In future versions the type checker might become a bit more versatile, and optional.

Comparision with Haskell/ML

The data type Tree given in "SYNOPSIS" would look like this in Haskell:

data Tree = Empty 
          | Leaf Int 
          | Node Tree Tree

In O'Caml you would write something like:

type tree = Empty 
          | Leaf of int
          | Node of tree * tree

We have no static type safety like Haskell. This is more the Perl way of doing it than the theoretical way.

SEE ALSO

Benjamin C. Pierce, Types and Programing Languages, chapter 11.10 for a theoretical view of how typed lambda calculus can be extened with variants (of little interest to most programmers but quite a nice book).

AUTHOR

Viktor Leijon <leijon@ludd.ltu.se>