On 21.03.2013 17:45, Carl Mäsak wrote:
> [...]
> 
> Using hashes and subclasses: <https://gist.github.com/masak/5213423> Using
> classes and subclasses: <https://gist.github.com/masak/5213563>
> 
> [...]

I came up with a prototype to create those classes like in the second gist
automatically by supplying a haskell-like declaration of the data type.

(skip to the end of the mail for the code)

Here's what it can do:

    my %res = create_adt("Tree = Branch Tree left, Tree right | Leaf Str 
storage");
    my \Tree = %res<Tree>;

    # create the tree with named parameters
    my $t =
        Tree.new-branch(
            :left(Tree.new-branch(
                :left(Tree.new-leaf(:storage(1))),
                :right(Tree.new-leaf(:storage(2))))),
            :right(Tree.new-leaf(:storage(3))));

    # create the tree with positional arguments
    my $t2 =
        Tree.new-branch(
            Tree.new-branch(
                Tree.new-leaf(1),
                Tree.new-leaf(2)),
            Tree.new-leaf(3));
    say $t2.gist;
    # outputs:  (reformatted for email)
    # Tree.new-branch(
    #        left => Tree.new-branch(
    #             left => Tree.new-leaf(storage => 1),
    #             right => Tree.new-leaf(storage => 2)),
    #        right => Tree.new-leaf(storage => 3))

    my \Branch = %res<Branch>;
    my \Leaf = %res<Leaf>;

    # haskell-style map for the tree
    sub treemap($t, *&code) {
        given $t {
            when Branch {
                return Tree.new-branch(
                        treemap($t.left, &code),
                        treemap($t.right, &code))
            }
            when Leaf {
                return Tree.new-leaf(code($t.storage))
            }
        }
    }

    say treemap($t2, * * 10).gist;
    # outputs:
    # Tree.new-branch(
    #        left => Tree.new-branch(
    #             left => Tree.new-leaf(storage => 10),
    #             right => Tree.new-leaf(storage => 20)),
    #        right => Tree.new-leaf(storage => 30))


There are currently some limitations:

1) there is no compiler support for checking that all cases have been covered,
   but as masak mentioned, I'm confident this can be done with a macro, because
   those run at compile-time basically.
2) you cannot yet use Leaf and Branch for declaring multi subs, because the
   symbols are not there at compile-time, but see below.
3) I have not yet figured out how to properly do pattern matching/decomposing,
   so the names "left", "right" and "storage" need to be supplied in the
   definition unlike in haskell.
4) I'm not sure how to do type parameters (think data Tree A = ...), because
   perl6 has only parametric roles, not parametric classes.

One thing rakudo needs to get for this to be much smoother is support for the
sub EXPORT to return a hash-like of symbols that will be installed in the
caller's package. This would make Tree, Branch and Leaf available as
compile-time symbols, so that multi methods/subs can use them for dispatch.

I mean to turn this into a module for the perl6 modules list some time in the
Future.

Finally, here's the runnable code. Feel free to play around with it and tell me
on this mailing list or the IRC channel what further problems (or even
solutions!) you find.

https://gist.github.com/timo/5226114

Have Fun!
  - Timo

Reply via email to