So: defining an operator is easy in Perl 6, and you can grab a new Unicode symbol for the operator. Dot product is just the sum of the pairwise product of the vectors' coordinates -- that's trivial to express using the hyper multiply and sum operators.
Let's step back and think about that for a moment. Except for the grouping parentheses, and final semicolon, there is nothing extraneous in the function body definition. It exactly implements the mathematical definition of dot product in code. Yet for about the same conceptual complexity as a strictly 3D, strictly working on doubles implementation in C++ or C#, the Perl 6 code is supremely flexible. It works on Vectors of any dimension. And it works on any pair of data types which, when multiplied, yield something that can be added. I believe it also implies that there is no significance to the ordering of the multiplications, meaning that a smart future Perl 6 can automatically parallelize them if the Vector is of large enough dimension to make it worthwhile.
As you can see from the code above, I have chosen to create a "Texas" version of the operator as well, spelling out "dot", for people who may have issues with Unicode. It is my strong belief that this should always be done. I have a great deal of sympathy for people whose favorite editor doesn't handle Unicode gracefully -- that was me until last fall. Even now, it's still easier to just type straightforward ASCII. I implemented the "dot" operator to call the dot operator following the DRY principle, even though it is probably less efficient than repeating the first function body again. (Is there a way to just alias a function/operator name to another operator?)
Let me go through my other stylistic decisions. I original wrote the body with a return statement. That matches my C++ experience, of course, but it is strictly optional in Perl 6. After thinking about it some (including how frequently I write closures where a return would seem bizarre), I decided that for one line functions like this, I would leave the return statement off. I think it is significantly more elegant this way.
I also initially left the "multi" off, just because I didn't realize it was ever needed. As I understand it, if I leave it off, I am defining THE dot product operator -- the only one it would try to call for any data type. That just plain seems rude to me. If nothing else, consider what would happen if code had to glue together two different vector types. (That may sound unlikely to you, but my work code frequently has to glue together three different vector types!) I can't think of a reason why library API functions would ever be anything but multi.
I am a bit bemused that I went with
$a
and $b
for the parameter names. In C++ I would traditional have chosen lhs
and rhs
, and my C# vector uses v1
and v2
. But $a
and $b
feels Perlish to me -- think of your classic sort code block.A word on error handling -- obviously there isn't any! If there is some sort of type error, Perl 6 will just report it when it happens. For lots of things, it will just DWIM no matter what strange types are thrown at it. The only error that worries me is if the Vectors do not have the same dimension. In that case the mathematical dot product is undefined, and Perl 6 will just merrily make up numbers to make the dimensions even. (I believe it will extend the array by repeating the last element in it.) I think that's fine for a toy system, but for a production system I'd want to signal an error in that case. I suspect the best way to do this is to add a
where
clause to the signature that checks that the second Vector has the same dimension as the first...
Just realized I forgot to address operator precedence, and in fact, have no idea how that works yet!
ReplyDelete