On 10/28/05, Christopher D. Malon <[EMAIL PROTECTED]> wrote: > On Oct 28, 2005, at 11:13 PM, Luke Palmer wrote: > Trying to think through the VectorSpace example, and a slightly > more complicated example (a Field), I'm starting to wonder whether > roles need to be parameterized somehow. (Maybe they already are? > This is one of my first p6 attempts, so bear with me...)
Oh yeah, roles can be parameterized. role VectorSpace[Field ^f] {...} role Field[AbelianGroup ^plus, Group ^times] {...} I'm intentionally handwaving over some details that are important. See below. > role Group should define a method "inverse()" whose implementation > is up to the class. inverse(operation => '+') or inverse(operation > => '*') > would make perfect sense. On an object that does Group only one way, > inverse() by itself would be okay, but it would be ambiguous > on a Field object. I don't know whether it's better for the interpreter > to produce a run-time error when a class implements a role in two ways > and the parameter isn't supplied, or if one implementation of a role > should > take priority. This is indeed the problem. A related problem is, let's say you have a utility sub for groups: # Group $x meaining an element of a group... that's a little strange sub power(Group $x, Int $pow) { given $pow { when $_ < 0 { power(inverse($x), -$pow) } when $_ == 0 { identity() } when $_ > 0 { $x * power($x, $pow - 1) } } } But what if you have a set that is a group under addition? That doesn't work, since you're trying to multiply here. sub power(Group[&infix:<*>] $x, Int $pow) { # same body as before } That assumes that Group has one parameter: the operation under which it is a group. Then you *bind* that parameter to a lexical infix:<*>, which means that when you say * within the body of your subroutine, you actually mean whatever operation the group defines. However, we still have a problem when we give a Field to power. Which group do we mean? One way to do this would be to pass an optional parameter: an object describing the group: sub power(Group $x, Int $pow, GroupDesc $desc = $x.desc) { given $pow { when $_ < 0 { power($desc.inverse($x), -$pow, $desc) } when $_ == 0 { $desc.identity } when $_ > 0 { $x * $desc.power($x, $pow - 1, $desc) } } } But that's starting to take away from the readability of the code, and it really takes away from the fact that Group is encoding the structure. There was a proposal in Haskell to have what they called "named instances", which addresses these kinds of problems: http://www.informatik.uni-bonn.de/~ralf/hw2001/4.pdf Perlizing the proposal, we might have something like: role Field[&infix:<+>, &infix:<*>] { does Group[&infix:<+>] FieldPlus; does Group[&infix:<*>] FieldTimes; ... } power(4, 3) (FieldPlus); # 12 power(4, 3) (FieldTimes); # 256 All group operations on a field would be on the Plus group if we're in a FieldPlus context, and conversely, all group operations on the field would be on the Times group if we're in a FieldTimes context. Exploring this issue further could be important to Perl's power when it comes to automatic dispatch. Luke