
my $expr =         ["Div", ["Con", 3],  
                ["Div", ["Con", 4], ["Con", 5]]]
;

        sub Eval {
          my $expr = shift;
          my ($op, $e1, $e2) = @$expr;
          if ($op eq "Con") {
                      Monad->do_print($e1)
            ->andThen(Monad->result($e1));
          } else {
            my ($v1, $v2);
                      Monad->do_print("[ ")
            ->andThen($v1 = Eval($e1))
            ->andThen(Monad->do_print(" divided by "))
            ->andThen($v2 = Eval($e2))
            ->andThen(Monad->do_print(" ]"))
            ->andThen(Monad->result($v1->value_of / $v2->value_of));
          }
        }

my $res = Eval($expr);
print "Returned value: ", $res->value_of, "\n";
print "Output: ", $res->output_of, "\n";

package Monad;

        # unit
        sub result {
          my ($class, $value) = @_;
          bless { VAL => $value, OUTPUT => "" } => $class;
        }

        # >>
        sub andThen {
          my ($a, $b) = @_;
          bless { VAL => $b->{VAL}, OUTPUT => $a->{OUTPUT} . $b->{OUTPUT} }
                 => ref $a;
        }

        sub value_of {
          my $self = shift;
          return $self->{VAL};
        }

        sub output_of {
          my $self = shift;
          return $self->{OUTPUT};
        }

        # Monad->do_print("some string");
        sub do_print {
          my ($class, $string) = @_;
          bless { VAL => undef, 
                  OUTPUT => $string } 
            => $class;
        }

