Skip to content

Instantly share code, notes, and snippets.

@myw
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save myw/522e0414628e80f4fbaf to your computer and use it in GitHub Desktop.
Save myw/522e0414628e80f4fbaf to your computer and use it in GitHub Desktop.
Common type constructs, done in Perl
package Direction;
# Simple algebraic types
sub North {
die 'Invalid type' unless @_ == 1;
bless(sub { 'North' }, shift)
}
sub South {
die 'Invalid type' unless @_ == 1;
bless(sub { 'South' }, shift)
}
package Int;
# Simple type with value constructor
sub Int {
die 'Invalid type' unless @_ == 1;
my $type = shift;
return sub {
my $value = shift;
# Value constructor constraints go here
die 'Invalid value' unless $value =~ /^\d+$/;
bless(sub { $value }, $type);
}
}
package List;
# Recursive, parameterized type
sub Empty {
die 'Invalid type' unless @_ == 2;
my $type = join('.', @_);
bless(sub { 'Empty' }, $type);
}
sub Cons {
die 'Invalid type' unless @_ == 2;
my $type = join('.', @_);
my $valuetype = $_[1];
return sub {
my $value = shift;
return sub {
my $list = shift;
# Value constructor constraints go here
die unless $value->isa($valuetype);
die unless $list->isa($type);
return bless(sub { $value, $list }, $type);
}
}
}
1;
### EXAMPLE USAGE
# REPL:42> List->Empty('Int')
# bless( sub {
# package List;
# 'Empty';
# }, 'List.Int' )
# REPL:43> List->Empty('Int')->()
# Empty
# REPL:44> List->Cons('Int')->(3)->(List->Empty('Int'))
# Runtime error: Can't call method "isa" without a package or object reference at Types.pm line 50.
# REPL:45> List->Cons('Int')->(Int->Int->(3))->(List->Empty('Int'))
# bless( sub {
# package List;
# $value, $list;
# }, 'List.Int' )
# REPL:46> List->Cons('Int')->(Int->Int->(3))->(List->Empty('Int'))->()
# [
# bless( sub {
# package Int;
# $value;
# }, 'Int' ),
# bless( sub {
# package List;
# 'Empty';
# }, 'List.Int' )
# ]
# REPL:47> List->Cons('Int')->(Int->Int->(3))->(List->Empty('Int'))->()[0]
# Runtime error: Not an ARRAY reference at (eval 2815) line 8.
# REPL:48> List->Cons('Int')->(Int->Int->(3))->(List->Empty('Int'))->()
# [
# bless( sub {
# package Int;
# $value;
# }, 'Int' ),
# bless( sub {
# package List;
# 'Empty';
# }, 'List.Int' )
# ]
# REPL:49> (List->Cons('Int')->(Int->Int->(3))->(List->Empty('Int'))->())[0]
# bless( sub {
# package Int;
# $value;
# }, 'Int' )
# REPL:50> (List->Cons('Int')->(Int->Int->(3))->(List->Empty('Int'))->())[0]->()
# 3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment