Data::Variant - Variant datatypes for perl.
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); }
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.
This function registers a variant with the module. The NAME should be a string uniquely naming the variant.
NAME
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
<NUM>
<STRING> - Strings
<STRING>
<REF> - References
<REF>
* - 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 *");
As a function, this function exports the variant named by the argument VARIANT to the calling module, making the constructors available in the module.
VARIANT
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.
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.
register_variant
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.
use vars qw{&Cons}
sub Cons
Note: The constructor will return an object with the appropriate data.
# 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";
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.
match
OBJ
CONS
VARLIST
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.
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.
switch
case
mkpat
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.
Presets an object to match against so that the first parameter of match can be left out in subsequent calls.
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.
croak
In future versions the type checker might become a bit more versatile, and optional.
The data type Tree given in "SYNOPSIS" would look like this in Haskell:
Tree
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.
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).
Viktor Leijon <leijon@ludd.ltu.se>
To install Data::Variant, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Data::Variant
CPAN shell
perl -MCPAN -e shell install Data::Variant
For more information on module installation, please visit the detailed CPAN module installation guide.