Nitpick my Perl6 - parametric roles
Anyone care to pick holes in this little expression of some Perl 6 core types as collections? I mean, other than missing methods ;) role Collection[\$types] { has Seq[$types] @.members; } role Set[::T = Item] does Collection[T] where { all(.members) =:= one(.members); }; role Pair[::K = Item, ::V = Item] does Seq[K,V] { method key of K { .[0] } method value of V { .[1] } }; role Mapping[::K = Item, ::V = Item] does Collection[Pair[K,V]] { all(.members).does(Pair) and all(.members).key =:= one(.members).key; } role Hash[Str ::K, ::V = Item] does Mapping[K, V] where { all(.members).key == one(.members).key } { method post_circumfix:<{ }> (K $key) of V|Undefined { my $seq = first { .key == $key } &.members; $seq ?? $seq.value :: undef; } } role ArrayItem[::V = Item] does Seq[Int, V] { method index of Int { .[0] } method value of Item { .[1] } }; role Array of Collection[ArrayItem] where { all(.members).index == one(.members).index } { method post_circumfix:<[ ]> (Int $index) of Item { my $seq = first { .index == $index } &.members; $seq ?? $seq.value :: undef; } } I'll take the feedback I get, and try to make a set of Perl 6 classes in the pugs project that look and feel just like regular Perl 6 hash/arrays but are expressed in more elementary particles. Cheers, Sam.
Re: Nitpick my Perl6 - parametric roles
HaloO, Sam Vilain wrote: Anyone care to pick holes in this little expression of some Perl 6 core types as collections? I mean, other than missing methods ;) My comments follow. role Collection[\$types] { has Seq[$types] @.members; } This is a little wrapper that ensures that collections have got a @.members sequence of arbitrary type. This immediately raises the question how Seq is defined. role Set[::T = Item] does Collection[T] where { all(.members) =:= one(.members); }; Nice usage of junctions! But how is the assertion of uniqueness transported into methods that handle adding of new values? In other words: I doubt that this comes freely out of the type systems inner workings but is more a statement of the intentions of a Set. Which leads to the question when this where clause will be checked or used to base MMD decisions. role Pair[::K = Item, ::V = Item] does Seq[K,V] { method key of K { .[0] } method value of V { .[1] } }; role Mapping[::K = Item, ::V = Item] does Collection[Pair[K,V]] { all(.members).does(Pair) and all(.members).key =:= one(.members).key; } I guess this is a typo and you wanted a where clause. The first assertion of the members doing the Pair role should be guaranteed by using Pair as the type argument when instantiating the Collection role. Are you sure that the underlying Seq type handles the one and two parameter forms you've used so far? role Hash[Str ::K, ::V = Item] does Mapping[K, V] Will the Str assertion not be too specific for non-string hashes? where { all(.members).key == one(.members).key } { method post_circumfix:<{ }> (K $key) of V|Undefined { Nice union type as return type. But isn't the type name Undef? my $seq = first { .key == $key } &.members; Wasn't that @.members? $seq ?? $seq.value :: undef; Ternary is spelled ?? !! now. } } role ArrayItem[::V = Item] does Seq[Int, V] { method index of Int { .[0] } method value of Item { .[1] } }; Here we see the two parameter version of Seq at work. role Array of Collection[ArrayItem] where { all(.members).index == one(.members).index } { method post_circumfix:<[ ]> (Int $index) of Item { my $seq = first { .index == $index } &.members; Is this first there a grep-like function? Shouldn't it then read 'first { .index == $index }, @.members'? $seq ?? $seq.value :: undef; } } I'll take the feedback I get, and try to make a set of Perl 6 classes in the pugs project that look and feel just like regular Perl 6 hash/arrays but are expressed in more elementary particles. This might be very useful in future debates about these types. But I think everything hinges on the basic Seq type. Regards, TSa. --
Re: Nitpick my Perl6 - parametric roles
TSa wrote: > role Set[::T = Item] does Collection[T] where { > all(.members) =:= one(.members); > }; Nice usage of junctions! But buggy - one means *exactly* one. So for an array of more than 1 element, all(@array) never equals one(@array) - if they're all the same, it's more than 1, otherwise it's 0. all(.members) =:= any(.members) would also not work, as it will try to match each member with some other or same member of the array. It will always return true, in other words, as each element of the array is equal to itself. This leaves all(.members) =:= .members[0], possibly extra with non-emptiness test. Miro
Re: Nitpick my Perl6 - parametric roles
HaloO, Miroslav Silovic wrote: TSa wrote: Nice usage of junctions! But buggy - one means *exactly* one. So for an array of more than 1 element, all(@array) never equals one(@array) - if they're all the same, it's more than 1, otherwise it's 0. Doesn't all(1,2,3) == one(1,2,3) expand the all junction first? So that we end up with 1 == one(1,2,3) && 2 == one(1,2,3) && 3 == one(1,2,3) which is true. In the case of duplicated entries we get a false if the one-junction supports that. That is, how does e.g. one(1,1,2) work? Is it failing for 1? Regards, --
Mutability vs Laziness
Carried over form IRC to placeholder the conversation as I saw it: We define the following in S06 as immutable types: ListLazy Perl list (composed of Seq and Range parts) Seq Completely evaluated (hence immutable) sequence Range Incrementally generated (hence lazy) sequence Set Unordered Seqs that allow no duplicates JunctionSets with additional behaviours PairSeq of two elements that serves as a one-element Mapping Mapping Pairs with no duplicate keys It seems to me that there are three core attributes, each of which has two states: Mutability: true, false Laziness: true, false Ordered: true, false There are, thus, eight types of containers, but two (unordered, mutable, lazy/eager) don't really work very well, so let's say 6: Ordered, Immutable, Eager: Seq Ordered, Immutable, Lazy: Range and/or Seq of Range? Ordered, Mutable, Eager: ? Ordered, Mutable, Lazy: Array Unordered, Immutable, Eager: Set Unordered, Immutable, Lazy: x and/or Set of x? In that last example, x is "an unordered range", though we don't have such a type. Basically, this is something like any(a..b). The real question in my mind, though is this: do we need to call something Lazy (as we currently do in S29), or should we just call it List or Array depending on its mutability?
[svn:perl6-synopsis] r12398 - doc/trunk/design/syn
Author: larry Date: Mon Sep 25 10:13:23 2006 New Revision: 12398 Modified: doc/trunk/design/syn/S02.pod doc/trunk/design/syn/S03.pod doc/trunk/design/syn/S06.pod Log: Slaughter of special [,], now is just listop form of [...] To support |func() syntax, | is the new * (desigilized) Modified: doc/trunk/design/syn/S02.pod == --- doc/trunk/design/syn/S02.pod(original) +++ doc/trunk/design/syn/S02.podMon Sep 25 10:13:23 2006 @@ -12,9 +12,9 @@ Maintainer: Larry Wall <[EMAIL PROTECTED]> Date: 10 Aug 2004 - Last Modified: 22 Sept 2006 + Last Modified: 25 Sept 2006 Number: 2 - Version: 71 + Version: 72 This document summarizes Apocalypse 2, which covers small-scale lexical items and typological issues. (These Synopses also contain @@ -670,7 +670,6 @@ @ ordered array % unordered hash (associative array) & code/rule/token/regex -| capture/arguments/match :: package/module/class/role/subset/enum/type/grammar @@ multislice view of @ @@ -818,22 +817,14 @@ $$args; # same as "$args as Scalar" or "Scalar($args)" @$args; # same as "$args as Array" or "Array($args)" %$args; # same as "$args as Hash" or "Hash($args)" -|$args; # all of the above When cast into an array, you can access all the positional arguments; into a hash, all named arguments; into a scalar, its invocant. -When stored in a variable using the C<|> sigil, the capture autointerpolates -into argument lists much like C<@> autoflattens into lists: - -|args := \($a, @b, :option($c)); -somefunc(|args); # same as somefunc($a, @b, :option($c)) - All prefix sigil operators accept one positional argument, evaluated in scalar context as a rvalue. They can interpolate in strings if called with parentheses. The special syntax form C<$()> translates into C<$( $/ )> -to operate on the current match object; the same applies to C<@()>, C<%()> and -C<|()> forms. +to operate on the current match object; the same applies to C<@()> and C<%()>. C objects fill the ecological niche of references in Perl 6. You can think of them as "fat" references, that is, references that @@ -2153,9 +2144,10 @@ =item * -The C<[,]> list operator may be used to force list context on its +The C<|> prefix operator may be used to force "capture" context on its argument and I defeat any scalar argument checking imposed by -subroutine signature declarations. This list flattens lazily. +subroutine signature declarations. Any resulting list arguments are +then evaluated lazily. =item * Modified: doc/trunk/design/syn/S03.pod == --- doc/trunk/design/syn/S03.pod(original) +++ doc/trunk/design/syn/S03.podMon Sep 25 10:13:23 2006 @@ -12,7 +12,7 @@ Maintainer: Larry Wall <[EMAIL PROTECTED]> Date: 8 Mar 2004 - Last Modified: 23 Sept 2006 + Last Modified: 25 Sept 2006 Number: 3 Version: 68 @@ -64,9 +64,8 @@ =item * Unary C<~> now imposes a string (C) context on its argument, and C<+> imposes a numeric (C) context (as opposed to being a no-op in Perl 5). Along the same lines, C imposes -a boolean (C) context, and the C<[,]> list operator imposes -a function-arguments (C) context on its arguments (as does -the C<|> sigil when used as an operator). +a boolean (C) context, and the C<|> unary operator imposes +a function-arguments (C) context on its argument. Unary sigils impose the container context implied by their sigil. As with Perl 5, however, C<$$foo[bar]> parses as C<( $($foo) )[bar]>, so you need C<$($foo[bar])> to mean the other way. @@ -906,14 +905,11 @@ return a boolean for either 1 or 0 arguments. Negated operators return C, and all the rest return C. -You can also make a reduce operator of the comma operator. This has -the effect of dereferencing its arguments into another argument list -as if they'd been placed there directly. +You can also make a reduce operator of the comma operator. This is just +the list operator form of the C<< circumfix:<[ ]> >> anonymous array composer: -@args = [EMAIL PROTECTED],1,2,3; -push [,] @args;# same as push(@foo: 1,2,3) - -See S06 for more. +[1,2,3]# make new Array: 1,2,3 +[,] 1,2,3 # same thing You may also reduce using the semicolon second-dimension separator: @@ -968,7 +964,7 @@ [^^]() # Bool::False [//]() # undef [=]() # undef(same for all assignment operators) -[,]() # () +[,]() # [] [¥]() # [] User-defined operators may define their own identity values, but @@ -1023,9 +1019,7 @@ and more obviously nonsensical.) A reduce operator returns only a scalar result regardless of context. -(Even C<[,]> returns a single C object which is then spliced -into the outer argument list.) To return all
Re: Mutability vs Laziness
Aaron Sherman wrote: It seems to me that there are three core attributes, each of which has two states: Mutability: true, false Laziness: true, false Ordered: true, false I think there's a 4th: exclusivity: whether or not duplicate elements are permitted/exposed (i.e. the difference between a set and a bag). This is orthogonal to orderedness.
Re: Nitpick my Perl6 - parametric roles
TSa wrote: >> role Collection[\$types] { >>has Seq[$types] @.members; >> } > This is a little wrapper that ensures that collections have got > a @.members sequence of arbitrary type. This immediately raises > the question how Seq is defined. > [...and later...] > Are you sure that the underlying Seq type handles the one and > two parameter forms you've used so far? Ah, yes, a notable omission. I understood a Seq as a list with individual types for each element, which are applied positionally. The superclass for things like Pair. Here's a quick mock-up of what I mean: role Seq[ \$types ] { submethod COMPOSE { # a la BUILD for classes loop( my $i = 0; $i < $types.elems; $i++ ) { # assumption: "self" here is the class # we're composing to, and "has" is a class # method that works a little like Moose self.has( $i++ => (isa => $types.[$i]) ); } } my subset MySeqIndex of Int where { 0 <= $_ < $types.elems }; method post_circimfix:<[ ]>( $element: MySeqIndex ) { $?SELF.$element; } } Seq is certainly interesting for various reasons. One is that it is a parametric role that takes an arbitrary set of parameters. In fact, it's possible that the type arguments are something more complicated than a list (making for some very "interesting" Seq types); the above represents a capture, but the above code treats it was a simple list. >> role Set[::T = Item] does Collection[T] where { >> all(.members) =:= one(.members); >> }; > > Nice usage of junctions! But how is the assertion of > uniqueness transported into methods that handle adding > of new values? I haven't defined any mutable state yet; it's still "pure". I'd expect mutability to be a different role, and a set of primitives that work on this level by returning a new set with the changes made. In fact the mutable Set could re-use those primitives, by just having a Set as a member (that 'handles' the Set role methods), and automatically changing that member each time a change is made, to point to the new Set with the new contents. Which all sounds very inefficient and scary until you realise what happens inside generative GC VMs that support STM. >> role Mapping[::K = Item, ::V = Item] does Collection[Pair[K,V]] { >> all(.members).does(Pair) and >> all(.members).key =:= one(.members).key; >> } > > I guess this is a typo and you wanted a where clause. The first > assertion of the members doing the Pair role should be guaranteed > by using Pair as the type argument when instantiating the Collection > role. Well spotted; yes, that is superfluous. >> role Hash[Str ::K, ::V = Item] does Mapping[K, V] > > Will the Str assertion not be too specific for non-string hashes? Another assumption I make here is that there is a basic type "Hash", which as its name suggests, is all about hashing strings, and that the more general form is called "Mapping" where any object can be the source, not just Str subtypes. Thanks for your other nitpicks and comments - much appreciated! Sam. >> where { all(.members).key == one(.members).key } >> { >> method post_circumfix:<{ }> (K $key) of V|Undefined { > > Nice union type as return type. But isn't the type name Undef? > >> my $seq = first { .key == $key } &.members; > > Wasn't that @.members? > >> $seq ?? $seq.value :: undef; > > Ternary is spelled ?? !! now. > > >> } >> } >> >> role ArrayItem[::V = Item] does Seq[Int, V] { >> method index of Int { .[0] } >> method value of Item { .[1] } >> }; > > Here we see the two parameter version of Seq at work. > > >> role Array of Collection[ArrayItem] >> where { all(.members).index == one(.members).index } >> { >> method post_circumfix:<[ ]> (Int $index) of Item { >> my $seq = first { .index == $index } &.members; > > Is this first there a grep-like function? Shouldn't it then > read 'first { .index == $index }, @.members'? > > >> $seq ?? $seq.value :: undef; >> } >> } >> >> I'll take the feedback I get, and try to make a set of Perl 6 classes in >> the pugs project that look and feel just like regular Perl 6 hash/arrays >> but are expressed in more elementary particles. > > This might be very useful in future debates about these types. But > I think everything hinges on the basic Seq type. > > > Regards, TSa.
Re: Mutability vs Laziness
Aaron Sherman wrote: > Carried over form IRC to placeholder the conversation as I saw it: > > We define the following in S06 as immutable types: > > ListLazy Perl list (composed of Seq and Range parts) > Seq Completely evaluated (hence immutable) sequence > Range Incrementally generated (hence lazy) sequence > Set Unordered Seqs that allow no duplicates > JunctionSets with additional behaviours > PairSeq of two elements that serves as a one-element Mapping > Mapping Pairs with no duplicate keys > > It seems to me that there are three core attributes, each of which has > two states: > > Laziness: true, false > Mutability: true, false > Ordered: true, false I don't think "Ordered" is an attribute of a collection other than in the abstract, user-centric sense - it is a type parameter difference (though also there are method differences etc). Things that are not ordered map from items to presence (or themselves, if you prefer). Things that are ordered map from array indices to items. > There are, thus, eight types of containers, but two (unordered, mutable, > lazy/eager) don't really work very well, so let's say 6: Mutable sets don't work? I don't see why not. > Ordered, Immutable, Eager: Seq > Ordered, Immutable, Lazy: Range and/or Seq of Range? > Ordered, Mutable, Eager: ? > Ordered, Mutable, Lazy: Array > Unordered, Immutable, Eager: Set > Unordered, Immutable, Lazy: x and/or Set of x? > > In that last example, x is "an unordered range", Sounds a bit like an iterator. Sam.
Common Serialization Interface
Both Data::Dumper and Storable provide hooks to customize serialization ($Data::Dumper::Freezer|Toaster, STORABLE_freeze|_thaw). Other modules like YAML and Clone could also possibly reuse a common state marshalling interface. Is there some common element to this process which can be gathered into a Serialize role with a default implementation? Does the meta information or object construction process change the needs for Perl 6? Brad -- It is written that the priest Shungaku said, "In just refusing to retreat from something one gains the strength of two men." This is interesting.-- Hagakure http://bereft.net/hagakure/
Re: Common Serialization Interface
Brad Bowman wrote: > > Both Data::Dumper and Storable provide hooks to customize serialization > ($Data::Dumper::Freezer|Toaster, STORABLE_freeze|_thaw). > Other modules like YAML and Clone could also possibly reuse a > common state marshalling interface. > > Is there some common element to this process which can be gathered > into a Serialize role with a default implementation? There is already ".yaml" to serialize to yaml and ".perl" to serialize to Perl (I'm not sure what the limits are round-tripping Perl this way). They can be returned to Perl in a consistent way, too: eval($yaml, :lang); Still, these options may not substitute for the kind of role-based solution you have mind. Mark
Re: Common Serialization Interface
On Mon, Sep 25, 2006 at 09:02:56PM -0500, Mark Stosberg wrote: : Brad Bowman wrote: : > : > Both Data::Dumper and Storable provide hooks to customize serialization : > ($Data::Dumper::Freezer|Toaster, STORABLE_freeze|_thaw). : > Other modules like YAML and Clone could also possibly reuse a : > common state marshalling interface. : > : > Is there some common element to this process which can be gathered : > into a Serialize role with a default implementation? : : There is already ".yaml" to serialize to yaml and ".perl" to serialize : to Perl (I'm not sure what the limits are round-tripping Perl this way). One thing that makes an enormous practical difference is whether the entire serialized string must be in memory or not. (I've been trying to work with a 37M yaml file recently, sigh...) : They can be returned to Perl in a consistent way, too: : : eval($yaml, :lang); : : Still, these options may not substitute for the kind of role-based : solution you have mind. I'm not sure it's wise to overload eval this way. Seems like a great way to defeat MMD. Plus I really want a file interface so I don't have to slurp a 37M string, which in turn requires a 400M stack allocation currently. Seems to want even more heap after that, and then it really starts thrashing... Larry
Re: Nitpick my Perl6 - parametric roles
On 9/25/06, Miroslav Silovic <[EMAIL PROTECTED]> wrote: TSa wrote: > > > role Set[::T = Item] does Collection[T] where { > > all(.members) =:= one(.members); > > }; > > Nice usage of junctions! > But buggy - one means *exactly* one. So for an array of more than 1 element, all(@array) never equals one(@array) - if they're all the same, it's more than 1, otherwise it's 0. Yeah, that would've been cool. Are we left with asserting C? That'd be pretty close to the original elegance. Ashley Winters
Re: Nitpick my Perl6 - parametric roles
At 7:28 PM -0700 9/25/06, Ashley Winters wrote: On 9/25/06, Miroslav Silovic <[EMAIL PROTECTED]> wrote: TSa wrote: > role Set[::T = Item] does Collection[T] where { > all(.members) =:= one(.members); > }; > Nice usage of junctions! But buggy - one means *exactly* one. So for an array of more than 1 element, all(@array) never equals one(@array) - if they're all the same, it's more than 1, otherwise it's 0. Yeah, that would've been cool. Are we left with asserting C? That'd be pretty close to the original elegance. Ashley Winters Unless I'm mistaken, you may be going about this the wrong way. Within a system that already has an underlying set-like type, the Junction in this case, a test for uniqueness is (pardon any spelling): all(@items).elements.size === @items.size The all() will strip any duplicates, so if the number of elements in all(@items) is the same as @items, then @items has no duplicates. Similarly, if @items is a list of Pair (such as when you're implementing a Mapping), and you want to assert that their keys are all distinct, then this variation (pardon any spelling) would do it: all(@items.map:{ .key }).elements.size === @items.size Incidentally, a unique-key constraint on an RM relation or table is like the latter as well, but substitute "key" for the name(s) of the attribute or column. On the other hand, if you're using the above Set to implement the Junction in the first place, we can't use all/any/one/none etc in the definition. -- Darren Duncan
[svn:perl6-synopsis] r12417 - doc/trunk/design/syn
Author: audreyt Date: Mon Sep 25 20:49:59 2006 New Revision: 12417 Modified: doc/trunk/design/syn/S02.pod doc/trunk/design/syn/S04.pod Log: * S02: Introduce the :$$x form in adverbial pair parsing. * S02/S04: Canonicalize "item" as the unary context enforcer, so that the name "Scalar" can unabiguous mean the mutable container class. Modified: doc/trunk/design/syn/S02.pod == --- doc/trunk/design/syn/S02.pod(original) +++ doc/trunk/design/syn/S02.podMon Sep 25 20:49:59 2006 @@ -12,9 +12,9 @@ Maintainer: Larry Wall <[EMAIL PROTECTED]> Date: 10 Aug 2004 - Last Modified: 25 Sept 2006 + Last Modified: 26 Sept 2006 Number: 2 - Version: 72 + Version: 73 This document summarizes Apocalypse 2, which covers small-scale lexical items and typological issues. (These Synopses also contain @@ -1481,6 +1481,8 @@ a => $a:$a a => @a:@a a => %a:%a +a => $$a :$$a +a => @$$a :@$$a (etc.) a => %foo %foo: Note that as usual the C<{...}> form can indicate either a closure or a hash @@ -2142,6 +2144,8 @@ really does exactly the same thing as putting a list in parentheses with at least one comma. But it's more readable in some situations.) +To force a non-flattening scalar context, use the "C" operator. + =item * The C<|> prefix operator may be used to force "capture" context on its Modified: doc/trunk/design/syn/S04.pod == --- doc/trunk/design/syn/S04.pod(original) +++ doc/trunk/design/syn/S04.podMon Sep 25 20:49:59 2006 @@ -12,9 +12,9 @@ Maintainer: Larry Wall <[EMAIL PROTECTED]> Date: 19 Aug 2004 - Last Modified: 24 Sep 2006 + Last Modified: 26 Sep 2006 Number: 4 - Version: 40 + Version: 41 This document summarizes Apocalypse 4, which covers the block and statement syntax of Perl. @@ -933,7 +933,7 @@ and not care about whether the function is being called in scalar or list context. To return an explicit scalar undef, you can always say -return scalar(undef); +return item(undef); Then in list context, you're returning a list of length 1, which is defined (much like in Perl 5). But generally you should be using