fp::lambda - lambda calculus in Perl


fp documentation Contained in the fp distribution.

Index


Code Index:

NAME

Top

fp::lambda - lambda calculus in Perl

SYNOPSIS

Top

  use fp::lambda;

  # add two Church numerals together
  add(\&two)->(\&two);

  # subtract them ...
  subtract(\&two)->(\&two);

  # check if a Church numeral is zero
  is_zero(\&zero); 

  # build a list of one through five
  my $one_through_five = cons(\&one)->(cons(\&two)->(cons(\&three)->(cons(\&four)->(cons(\&five)->(\&NIL)))));

  # check it's size
  is_equal(size($one_through_five))->(\&five);

  # get the sum of the list
  sum($one_through_five)); # returns 15 (as a Church numeral)

DESCRIPTION

Top

This module implements lambda calculus using plain Perl subroutines as lambda abstractions.

FUNCTIONS

Top

Church Booleans

TRUE := &955; x. &955; y. x
FALSE := &955; x. &955; y. x
AND := &955; p. &955; q. p q FALSE
OR := &955; p. &955; q. p TRUE q
NOT := &955; p. p FALSE TRUE
cond := &955; p. &955; x. &955; y. p x y

Church Numerals

zero := &955; f. &955; x. x
one := &955; f. &955; x. f x
two := &955; f. &955; x. f (f x)
three := &955; f. &955; x. f (f (f x))
four := &955; f. &955; x. f (f (f (f x)))
five := &955; f. &955; x. f (f (f (f (f x))))
six := &955; f. &955; x. f (f (f (f (f (f x)))))
seven := &955; f. &955; x. f (f (f (f (f (f (f x))))))
eight := &955; f. &955; x. f (f (f (f (f (f (f (f x)))))))
nine := &955; f. &955; x. f (f (f (f (f (f (f (f (f x))))))))
ten := &955; f. &955; x. f (f (f (f (f (f (f (f (f (f x)))))))))
succ := &955; n. &955; f. &955; x. f (n f x)
pred := &955; m. first (m (&955; p. pair (second p) (plus one (second p))) (pair zero zero))
is_zero := &955; n. n (&955; x. FALSE) TRUE
is_equal := &955; m. &955; n. AND (is_zero (m pred n)) (is_zero (n pred m))
plus := &955; m. &955; n. &955; f. &955; x. m f (n f x)
subtract := &955; m. &955; n. n pred m
multiply := &955; m. &955; n. m (plus n) zero

List Functions

NIL := pair TRUE TRUE
is_NIL := first
is_not_NIL := &955; x. NOT is_NIL
cons := &955; h. &955; t. pair FALSE (pair h t)
head := &955; z. first (second z)
tail := &955; z. second (second z)
size := &955; l. cond (is_not_NIL l) (&955; x. succ (size (tail l))) (&955; l. zero)
sum := &955; l. cond (is_not_NIL l) (&955; x. plus (head l) (sum (tail l))) (&955; l. zero)
append := &955; l1. &955; l2. cond (is_NIL l1) (l2) (cons (head l1) (append (tail l1) l2))
rev := &955; l. cond (is_not_NIL) (NIL) (append rev(tail l) cons((head l) NIL))
nth := &955; n. &955; l. cond (is_NIL l) (NIL) (cond (is_equal n zero) (head l) (nth (pred n)) (tail l)) )
apply := &955; f. &955; l. cond (is_NIL l) (NIL) (cons (f (head l)) (apply f (tail l)))

Pair Functions

pair := &955; f. &955; s. &955; b. b f s
first := &955; p p TRUE
second := &955; p p FALSE

BUGS

Top

None that I am currently aware of. Of course, that does not mean that they do not exist, so if you find a bug, let me know, and I will be sure to fix it.

CODE COVERAGE

Top

See the CODE COVERAGE section of fp for this information.

SEE ALSO

Top

Types and Programming Languages
http://en.wikipedia.org/wiki/Lambda_calculus
http://www.csse.monash.edu.au/~lloyd/tildeFP/Lambda/

AUTHOR

Top

stevan little, <stevan@iinteractive.com>

COPYRIGHT AND LICENSE

Top


fp documentation Contained in the fp distribution.

package fp::lambda;

use strict;
use warnings;

our $VERSION = '0.01';

BEGIN {
    require fp;
    *import = \&fp::import;
}

## Church Booleans

# TRUE := λ x. λ y. x
*TRUE = sub {
    my $x = shift;
    sub { $x }
};

# FALSE :=  λ x. λ y. x
*FALSE = sub {
    my $x = shift;
    sub { shift }
};

# AND := λ p. λ q. p q FALSE
*AND = sub {
    my $p = shift;
    sub {
        my $q = shift;
        $p->($q)->(\&FALSE);
    }
};

# OR := λ p. λ q. p TRUE q
*OR = sub {
    my $p = shift;
    sub {
        my $q = shift;
        $p->(\&TRUE)->($q);
    }
};

# NOT := λ p. p FALSE TRUE
*NOT = sub {
    my $p = shift;
    $p->(\&FALSE)->(\&TRUE);
};

# cond := λ p. λ x. λ y. p x y
*cond = sub {
    my $p = shift;
    sub {
        my $x = shift;
        sub {
            my $y = shift;
            $p->($x)->($y);
        }
    }
};

## Church Numeral 

# 0 := λ f. λ x. x
*zero = sub { 
    my $f = shift; 
    sub { shift } 
};

# succ := λ n. λ f. λ x. f (n f x)
*succ = sub { 
    my $n = shift; 
    sub { 
        my $f = shift; 
        sub { 
            my $x = shift; 
            $f->( $n->($f)->($x) ) 
        } 
    } 
};

# pred := λ m. first (m (λ p. pair (second p) (plus one (second p))) (pair zero zero))
*pred = sub {
    my $m = shift;
    sub {
        first($m->(sub {
                my $p = shift;
                pair(second($p))->(plus(\&one)->(second($p)))
            })->(pair(\&zero)->(\&zero)))
    }->()
};

# plus := λ m. λ n. λ f. λ x. m f (n f x)
*plus = sub { 
    my $m = shift; 
    sub { 
        my $n = shift; 
        sub { 
            my $f = shift; 
            sub { 
                my $x = shift; 
                $m->( $f )->( $n->($f)->($x) ) 
            } 
        } 
    } 
};

# subtract := λ m. λ n. n pred m
*subtract = sub {
    my $m = shift;
    sub {
        my $n = shift;
        $n->(\&pred)->($m);
    }
};

# multiply := λ m. λ n. m (plus n) zero 
*multiply = sub {
    my $m = shift;
    sub {
        my $n = shift;
        $m->(plus($n))->(\&zero);
    }
};

# now make 1 .. 10 

*one   = succ(\&zero);
*two   = succ(\&one);
*three = succ(\&two);
*four  = succ(\&three);
*five  = succ(\&four);
*six   = succ(\&five);
*seven = succ(\&six);
*eight = succ(\&seven);
*nine  = succ(\&eight);
*ten   = succ(\&nine);

## Predicates

# is_zero := λ n. n (λ x. FALSE) TRUE
*is_zero = sub {
    my $n = shift;
    $n->(sub { \&FALSE })->(\&TRUE);
};

# is_equal := λ m. λ n. and (is_zero (m pred n)) (is_zero (n pred m))
*is_equal = sub {
    my $m = shift;
    sub {
        my $n = shift;
        AND(
            is_zero($m->(\&pred)->($n))
        )->(
            is_zero($n->(\&pred)->($m))
        )
    }
};

## Data Structures

## Pairs

# pair := λ f. λ s. λ b. b f s
*pair = sub {
    my $f = shift;
    sub {
        my $s = shift;
        sub {
            my $b = shift;
            $b->($f)->($s);
        }
    }
};

# first := λ p p TRUE
*first = sub {
    my $p = shift;
    $p->(\&TRUE)
};

# second := λ p p FALSE
*second = sub {
    my $p = shift;
    $p->(\&FALSE)
};

# List functions

# NIL := pair TRUE TRUE
*NIL = pair(\&TRUE)->(\&TRUE);

# cons := λ h. λ t. pair FALSE (pair h t)
*cons = sub {
   my $h = shift;
   sub {
       my $t = shift;
       pair(\&FALSE)->(pair($h)->($t));
   }  
};

# head := λ z. first (second z)
*head = sub {
    my $z = shift;
    first(second($z));
};

# tail := λ z. second (second z)
*tail = sub {
    my $z = shift;
    second(second($z));
};

# is_NIL := first
*is_NIL = \&first;

# is_not_NIL := λ x. NOT is_NIL
*is_not_NIL = sub {
    my $x = shift;
    NOT(is_NIL($x))
};

# size := λ l. cond (is_not_NIL l) (λ x. succ (size (tail l))) (λ l. zero)
*size = sub {
    my $l = shift;
    cond(is_not_NIL($l))->(
        # have to wrap this to get lazy evaluation
        sub { succ(size(tail($l))) }
    )->(
        sub { \&zero }
    )->();
};

# sum := λ l. cond (is_not_NIL l) (λ x. plus (head l) (sum (tail l))) (λ l. zero)
*sum = sub {
    my $l = shift;
    cond(is_not_NIL($l))->(
        sub { plus(head($l))->(sum(tail($l))) }
    )->(
        sub { \&zero }
    )->()
};

# append := λ l1. λ l2. cond (is_NIL l1) (l2) (cons (head l1) (append (tail l1) l2))  
*append = sub {
    my $l1 = shift;
    sub {
        my $l2 = shift;
        cond(is_NIL($l1))->(
            sub { $l2 }
        )->(
            sub { cons(head($l1))->(append(tail($l1))->($l2)) }
        )->();
    }
};

# rev := λ l. cond (is_not_NIL) (NIL) (append rev(tail l) cons((head l) NIL))
*rev = sub {
    my $l = shift;
    cond(is_not_NIL($l))->(
        sub { append(rev(tail($l)))->(cons(head($l))->(\&NIL)) }
    )->(
        sub { \&NIL }
    )->()
};


# nth := λ n. λ l. cond (is_NIL l) (NIL) (cond (is_equal n zero) (head l) (nth (pred n)) (tail l)) ) 
*nth = sub {
  my $n = shift;
  sub {
      my $l = shift;
      cond(is_NIL($l))->(
          sub { \&NIL }
      )->(
          cond(is_equal($n)->(\&zero))->(
              sub { head($l) }
          )->(
              sub { nth(pred($n))->(tail($l)) }
          )
      )->()
  }  
};

# apply := λ f. λ l. cond (is_NIL l) (NIL) (cons (f (head l)) (apply f (tail l)))
*apply = sub {
    my $f = shift;
    sub {
        my $l = shift;
        cond(is_NIL($l))->(
            sub { \&NIL }
        )->(
            sub { cons($f->(head($l)))->(apply($f)->(tail($l))) }
        )->()
    }
};

1;

__END__