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