Re: A common and useful thing that doesn't appear to be easy in Perl 6
One more idea: could you implement the sort of thing being asked for by means of a buffer? That is, what's the difference between the bitset being asked for and a Buf[boolean]? And could those differences be addressed by composing a Buf[boolean] into a more appropriate role? Note also that Perl 6 allows for user-defined array indices. Since strings and buffers borrow array syntax for the purpose of accessing individual components, should it not be possible to define a customized index for a boolean buffer? Something like: my $flags is Buf[boolean]{ }; Again, I'm not sure as to the exact syntax; but it seems to me that something along these lines should be doable. -- Jonathan "Dataweaver" Lang
Re: A common and useful thing that doesn't appear to be easy in Perl 6
On Wed, 7 Apr 2010, yary wrote: > 2010/4/6 Larry Wall : > > Set(Read | Write) # bogus, R|W is really 3 sets, R, W, and RW! > > Set(Read & Write) # okay, can only represent RW > > Set(A | B) doesn't seem so bogus to me, if what you want is the power > set Hmm, surely a power-set would be written as Set(Set(X,Y,...)) or perhaps more mathematically as 2 ** Set(X,Y,...) -Martin
Re: A common and useful thing that doesn't appear to be easy in Perl 6
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 On Apr 7, 2010, at 00:52 , Larry Wall wrote: more syntactic and/or semantic sugar. It's just a bit awkward, after you say: enum Permissions ; subset Perms of Set of Permissions; that the name of the single-member sets are Perms(Read) Perms(Write) Perms(Exec) I'm not sure that is a problem; if nothing else, it looks a lot like a namespace. - -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allb...@kf8nh.com system administrator [openafs,heimdal,too many hats] allb...@ece.cmu.edu electrical and computer engineering, carnegie mellon universityKF8NH -BEGIN PGP SIGNATURE- Version: GnuPG v2.0.10 (Darwin) iEYEARECAAYFAku88H0ACgkQIn7hlCsL25UMygCghfC0kT1tW+1TmVNsmFkK+Dt1 e6MAnRl5U0F+LS/7pztfqA2IZToDBvGG =4KcO -END PGP SIGNATURE-
Re: A common and useful thing that doesn't appear to be easy in Perl 6
2010/4/6 Larry Wall : > Set(Read | Write) # bogus, R|W is really 3 sets, R, W, and RW! > Set(Read & Write) # okay, can only represent RW Set(A | B) doesn't seem so bogus to me, if what you want is the power set- not the original posters intent, but reasonable in other contexts. Though it's not quite the power set of A,B since it omits the empty set. Still, I wonder if special-casing passing a junction to a set is helpful. Why write Set (A & B) when you mean Set(A,B), and what if you want a set of junctions, e.g. Set(A&B, B|C)?
Re: A common and useful thing that doesn't appear to be easy in Perl 6
> We could make enum declarators even more like constant declarators > by using a pseudo assignment. Then we could use = instead of parens: > > enum Perms = Z=> 1,2,4...*; Hmm. That doesn't seem very like constant declarators. In a constant declarator, the constant appears on the lhs and its value on the rhs. In this proposal, the constants all appear on the rhs, along with the values. Besides, enums are type declarators, not (just) object declarators, and no other type declarator uses a pseudo-assignment, does it? If we wanted enums to use something more like the constant declarator syntax, I'd have thought: enum Perms = 1,2,4...*; was a much closer analog (and syntactically cleaner too). Damian
Re: A common and useful thing that doesn't appear to be easy in Perl 6
Jonathan Lang wrote: > Wouldn't that be C< = 0...* >? Indeed. Thanks for the correction. > That said, don't we already have a means of assigning specific values > to individual members of an enum? I forget the exact syntax, The exact syntax is: enum Perms [Read => 1, Write => 2, Exec => 4, Fold => 8, Spindle => 16, Mutilate => 32] or enum Perms << :Read(1), :Write(2), :Exec(4), :Fold(8), :Spindle(16), :Mutilate(32) >> or any other variation that uses a list of pairs. > Clumsy, sure; The clumsiness isn't the main problem, in my view; the explicitness of having to provide the values is. Even the hyperoperated version (which isn't currently legal, BTW) requires an explicit series to generate the values. Yet the whole point of enums is to avoid explicitly enumerating the values (as far as possible). The secondary point here is that an enum type doesn't solve the original problem, since it won't allow combinations of enumerated values: enum Perms [Read => 1, Write => 2, Exec => 4, Fold => 8, Spindle => 16, Mutilate => 32]; my Perms $perms = Read +| Write; # Error I'm now strongly convinced that a module is the right answer here. We have the need for a datatype that is essential is a couple of domains, but much better handled via Sets in most other contexts. So it's inherently a special-purpose datatype, and hence not appropriate in the core language. And Perl 6 already provides the macro mechanism needed to allow such a datatype to be seamlessly added with a convenient and "natural" syntax. Which is what I shall eventually do, I suspect. In that sense this discussion *vindicates* the current design, demonstrating that it provides the necessary flexibility and tools to allow someone to implement a new datatype and declarator syntax and integrate them seamlessly into the language, without having to redefine the language itself...or modify the compiler. Damian
Re: A common and useful thing that doesn't appear to be easy in Perl 6
On Wed, Apr 07, 2010 at 06:33:46AM -0700, Jon Lang wrote: : That said, don't we already have a means of assigning specific values : to individual members of an enum? I forget the exact syntax, but I : believe that it involves an assignment operator within the : enumeration. Mind you, this is from memory: : : enum Perms { Read = 1, Write = 2, Exec = 4, Fold = 8, Spindle = : 16, Mutilate = 32 } : : ...or something to that effect. Clumsy, sure; but it seems to me that : this is exactly the sort of thing that hyper-operators were designed : to handle: : : enum Perms { Read, Write, Exec, Fold, Spindle, Mutilate } »=« (1, : 2, 4 ... 32) : enum Perms { Read, Write, Exec, Fold, Spindle, Mutilate } »=» (1, : 2, 4 ... *) : : ...or something along those lines. I'll check the exact syntax later, : when I have more time; but I wonder if something to this effect is : already possible with the language spec as written. You're right, though you're reaching for the wrong meta-operator, since hypers have parallel and run-to-completion semantics, and therefore don't like infinite lists. Instead, you want a nice, ordered, lazy, "zipwith". In the currently specced syntax, that would be: enum Perms ( Z=> 1,2,4...*); That just creates a list of pairs, and stops at the end of the shorter list. Which is exactly what we want. The parens are necessary because the enum declaration currently takes a single list term which is tighter than comma, syntactically speaking. We could make enum declarators even more like constant declarators by using a pseudo assignment. Then we could use = instead of parens: enum Perms = Z=> 1,2,4...*; This works because list infix is tighter than list assignment. I've been thinking of switching enums to this form for some time, and this may tip me over the edge. (Presuming of course that I wasn't tipped over the edge many years ago...) Larry
Re: A common and useful thing that doesn't appear to be easy in Perl 6
Damian Conway wrote: > I do like the idea of being able to specify the sequence of values of an > enumeration by using a series of some kind. > > And I must say the one that feels most natural is the one that plays on > the equivalence of underlying equivalence of enums and constants, namely: > > enum Perms = 1,2,4...*; > > This would also mean you could think of a "normal" enum: > > enum Days ; > > as simply defaulting to C< = 1...* >. Wouldn't that be C< = 0...* >? That said, don't we already have a means of assigning specific values to individual members of an enum? I forget the exact syntax, but I believe that it involves an assignment operator within the enumeration. Mind you, this is from memory: enum Perms { Read = 1, Write = 2, Exec = 4, Fold = 8, Spindle = 16, Mutilate = 32 } ...or something to that effect. Clumsy, sure; but it seems to me that this is exactly the sort of thing that hyper-operators were designed to handle: enum Perms { Read, Write, Exec, Fold, Spindle, Mutilate } »=« (1, 2, 4 ... 32) enum Perms { Read, Write, Exec, Fold, Spindle, Mutilate } »=» (1, 2, 4 ... *) ...or something along those lines. I'll check the exact syntax later, when I have more time; but I wonder if something to this effect is already possible with the language spec as written. -- Jonathan "Dataweaver" Lang
Re: A common and useful thing that doesn't appear to be easy in Perl 6
Daniel Ruoso pointed out: > Using bitsets in Perl 6 is just as easy as using in Perl 5 -- which > happens to be the same as using in C, but it's not C... > > constant PERM_WRITE = 0b0001; > constant PERM_READ = 0b0010; > constant PERM_EXEC = 0b0100; > constant PERM_NAMES = { PERM_WRITE => 'Write', >PERM_READ => 'Read', >PERM_EXEC => 'Exec' }; > subset Perm of Int where * < 8; Sure. This certainly works, but the technique requires the developer to hard-code each name twice and to hard-code the constant 8 as well. This seems unfortunately brittle from a maintainability point of view. I know hardware engineers aren't supposed to care about maintainability, but I'd like us to make it easier for them to do the right thing than not. ;-) > The thing that bugs me is that sets have way more uses then bitsets, and > we might be overspecializing sets to support that semantics. Yes. I have the same concern. > If there's a strong case for bitsets, maybe it's worth having a > specialized declarator. Or maybe it doesn't need to be core syntax at all and I just need to create a module that implements my original dream syntax/semantics; namely a macro implementing a C type declarator that allows: use Type::Bitset; bitset Perms ; # Declares enumerated constants with successive powers-of-two values # Also declares: subset Perms of Int where 0 .. [+|] @constant_values; # Hence allows: my Perms $perms = Read +| Write +| Mutilate; # Okay my Perms $bad_perms = Read +| Write +| 42; # Error Aw heck, now that I've specified it, the implementation is just a SMOP. Forget I asked. I'll just write it myself! ;-) Damian
Re: A common and useful thing that doesn't appear to be easy in Perl 6
Larry mused: > Alternatively, maybe there should be some way to express infinite sets. > Not sure I like the idea of an infinite junction, but something resembling: > > subset PowersOf2 of Int where any(1,2,4...*) > enum Perms of PowersOf2 ; > say Exec; # 4 > > Presumably the series in the junction would have to be sufficiently > monotonic so we can know when we've looked far enough. Or we just > allow something like one of: > > subset PowersOf2 is Set(1,2,4...*); > constant PowersOf2 = Set(1,2,4...*); > > In any case, the idea is that an enum of something like PowersOf2 would > be smart enough not to use values that aren't in the 'of' type. I do like the idea of being able to specify the sequence of values of an enumeration by using a series of some kind. And I must say the one that feels most natural is the one that plays on the equivalence of underlying equivalence of enums and constants, namely: enum Perms = 1,2,4...*; This would also mean you could think of a "normal" enum: enum Days ; as simply defaulting to C< = 1...* >. > We've got these silly series operators; it seems a shame not to use > them for powers of two when appropriate. I certainly agree there. Damian
Re: A common and useful thing that doesn't appear to be easy in Perl 6
Em Ter, 2010-04-06 às 22:19 -0700, Damian Conway escreveu: > > I kinda hope we can get a bit further away from the machine code > > level of reality one of these decades. Perl 6 should not be > > optimized for C semantics. > Agreed. But it should at least support those who need to work at > the machine code level, but would prefer not to have to do so in C. While I agree with all the reasoning... I just like to point that currently they are not required to do so in C. Using bitsets in Perl 6 is just as easy as using in Perl 5 -- which happens to be the same as using in C, but it's not C... constant PERM_WRITE = 0b0001; constant PERM_READ = 0b0010; constant PERM_EXEC = 0b0100; constant PERM_NAMES = { PERM_WRITE => 'Write', PERM_READ => 'Read', PERM_EXEC => 'Exec' }; subset Perm of Int where * < 8; my Perm $perm = PERM_WRITE +| PERM_READ; if ($perm +& PERM_WRITE) { say 'can write' } my @names = map { PERM_NAMES{$_} }, grep { $_ +& $perm }, (PERM_WRITE, PERM_READ, PERM_EXEC); > That said, I'd be perfectly happy to encourage the use of proper set > abstractions for this purpose, so long as the long-suffering hardware > engineers can still easily convert the final set to an appropriate > bit-pattern when it's time to pump the results out to the hardware. The thing that bugs me is that sets have way more uses then bitsets, and we might be overspecializing sets to support that semantics. Because proper set abstractions won't allow you to explicitly define how the bitset is composed (which member has each value) -- at least I dont' see it at this point -- since that's just an optimization because you're dealing with a set of small integers. If there's a strong case for bitsets, maybe it's worth having a specialized declarator. daniel
Re: A common and useful thing that doesn't appear to be easy in Perl 6
On Tue, Apr 06, 2010 at 10:19:15PM -0700, Damian Conway wrote: : Larry concluded: : : > I do freely admit that most Perlfolk are not used to thinking of : > permissions in terms of set theory. But as I said, we're looking at : > kind of a strange use case here, and perhaps not typical of the kinds : > of sets of small numbers that people will be using in the future. : : The reason I raised the issue is because I believe it *is* a very : typical use-case...in certain hardware-oriented domains. : : : > I kinda hope we can get a bit further away from the machine code : > level of reality one of these decades. Perl 6 should not be : > optimized for C semantics. : : Agreed. But it should at least support those who need to work at : the machine code level, but would prefer not to have to do so in C. : : That said, I'd be perfectly happy to encourage the use of proper set : abstractions for this purpose, so long as the long-suffering hardware : engineers can still easily convert the final set to an appropriate : bit-pattern when it's time to pump the results out to the hardware. Another possibility would be to go ahead and have the numbers be powers of two, but have the sets smart enough about *those* rather than the small integers. Then we'd need some kind of sugar like enum Perms of (1,2,4...*) ; or with a more constant-declaring-like syntax: enum Perms = 1,2,4...*; Alternatively, maybe there should be some way to express infinite sets. Not sure I like the idea of an infinite junction, but something resembling: subset PowersOf2 of Int where any(1,2,4...*) enum Perms of PowersOf2 ; say Exec; # 4 Presumably the series in the junction would have to be sufficiently monotonic so we can know when we've looked far enough. Or we just allow something like one of: subset PowersOf2 is Set(1,2,4...*); constant PowersOf2 = Set(1,2,4...*); In any case, the idea is that an enum of something like PowersOf2 would be smart enough not to use values that aren't in the 'of' type. We've got these silly series operators; it seems a shame not to use them for powers of two when appropriate. Larry
Re: A common and useful thing that doesn't appear to be easy in Perl 6
Larry concluded: > I do freely admit that most Perlfolk are not used to thinking of > permissions in terms of set theory. But as I said, we're looking at > kind of a strange use case here, and perhaps not typical of the kinds > of sets of small numbers that people will be using in the future. The reason I raised the issue is because I believe it *is* a very typical use-case...in certain hardware-oriented domains. > I kinda hope we can get a bit further away from the machine code > level of reality one of these decades. Perl 6 should not be > optimized for C semantics. Agreed. But it should at least support those who need to work at the machine code level, but would prefer not to have to do so in C. That said, I'd be perfectly happy to encourage the use of proper set abstractions for this purpose, so long as the long-suffering hardware engineers can still easily convert the final set to an appropriate bit-pattern when it's time to pump the results out to the hardware. Damian
Re: A common and useful thing that doesn't appear to be easy in Perl 6
On Tue, Apr 06, 2010 at 08:47:11PM -0700, Geoffrey Broadwell wrote: : First: what Damian said. : : Second: Whatever syntax people come up with has to make it easy and : type-safe to name particular combinations of those bits. : : In other words, you should be able to make a bitset with Unix-style : permissions: : : OTHER_EXECUTE : OTHER_WRITE : OTHER_READ : GROUP_EXECUTE : GROUP_WRITE : GROUP_READ : ... You use that word 'bitset', but real sets would be better, if they can also behave like bitsets at need. : But still be able to make bitmasks (ignore the syntax here): : : OTHER_MASK = OTHER_READ +| OTHER_WRITE +| OTHER_EXECUTE; : GROUP_MASK = GROUP_READ +| GROUP_WRITE +| GROUP_EXECUTE; : ... : : These bitmasks should be properly typed with respect to the original : bitset; which is to say, this should work: : : my Permissions $other_perms = $file_perms +& OTHER_MASK; Well, I suppose we could do violence to the operator and overload it between set types, but I think of +& as a coercion to numeric types, with a return of a number, not a set. So I think, as I mentioned in my other message, that it would be good to stay away from the numeric bitops if you really want type safety. What you're really wanting is more like: my Perms $other_perms = $file_perms ∩ $interesting_perms; or more Texasly: my Perms $other_perms = $file_perms (*) $interesting_perms; in which case the intersection returns a set, not a number. I do freely admit that most Perlfolk are not used to thinking of permissions in terms of set theory. But as I said, we're looking at kind of a strange use case here, and perhaps not typical of the kinds of sets of small numbers that people will be using in the future. I kinda hope we can get a bit further away from the machine code level of reality one of these decades. Perl 6 should not be optimized for C semantics. Larry
Re: A common and useful thing that doesn't appear to be easy in Perl 6
On Tue, Apr 06, 2010 at 08:31:24PM -0700, Damian Conway wrote: : An issue came up in a class I was teaching today... : : There doesn't seem to be an easy way to create a type that allows a set : of enumerated bit-flags *and* all the combinations of those flags...and : nothing else. : : For example: : : enum Permissions ( Read => 0b0001, Write => 0b0010, Exec => 0b0100 ); : : my Permissions $rwx = Read +| Write;# Error I think we're getting hung up on powers-of-two here, and the low-level implementation details of stuffing bits into numbers. Instead, I think we should take a hint from that ancient tongue, Pascal, and simply make sets of small integers do the right thing with respect to bitmaps. Then normal enum semantics can provide those small integers, and all the powers-of-two business is implicit in the construction of the set: enum Permissions ; subset Perms of Set of Permissions; my $rwx = Perms(Read,Write); say $rwx.perl; # Perms(Read,Write) or some scuh say ~$rwx # "Read Write" say $rwx.elems; # 2 say +$rwx; # 3 That is, the numeric value would be suitable for ORin into any numeric set of permissions. Sets based on types that are not amenable to representation as bitmaps would, of course, not produce a meaningful numeric value. Alternately, + could return the same as .elems, and a different method could be used to get the bitmap, but then it becomes harder to write expressions using the bitmaps. Perhaps that's a feature. Also, while presumably Int can hold a bitset of any size, we might also want to play with bitsets represented as strings. We could overload stringification for that, but that would likely be a mistake. The string forms of such sets should probably remain human readable. : I know I could use junctions: : : subset BitFlag where Read|Write|Exec; : : my BitFlag $rwx = Read | Write; : : but it's not easy to recover the actual bitpattern from that, except with: : : $bitpattern = [+|] $rwx.eigenstates; : : which is suboptimal in readability (not to mention that it requires : MONKEY_TYPING to allow access to the .eigenstates method). To the extent that Junctions can be mapped to Sets, it's actually only "all" junctions that correspond precisely to strict definition of a set. That is, a set is defined as all of its members. It is very much *not* a container for some subset of its members. Hence, it might be permissible to convert an "all" junction to a set without invoking any monkey business. Set(Read | Write) # bogus, R|W is really 3 sets, R, W, and RW! Set(Read & Write) # okay, can only represent RW (assuming here that the Set coercion can be passed a junction without autothreading). : Ideally, what I'd like to be able to do is something like: : : enum Permissions is bitset < Read Write Exec >; : : # The 'is bitset' starts numbering at 0b0001 (instead of the usual zero) : # and doubles each subsequent enumeration value (instead of the usual ++). : # It also implicitly fills in the various other bitwise-or permutations : # as valid-but-nameless enumerated values : : my Permissions $rwx = Read +| Write;# Now fine If you really want to use +| and friends for their innate *cough* beauty, you can still do so--presuming these bitmapping sets numerify to the correct bitmap. However, I suspect some people might prefer (or come to prefer) using set operators, particularly as these get used for collections that people think of more as sets. In this sense, starting out with a use case based on low-level file status bits is perhaps not most indicative of the best way forward. : The closest I can think of at the moment is something like: : : enum NamedPermissions ( Read => 0b0001, Write => 0b0010, Exec => 0b0100 ); : : subset Permissions of Int where 0 .. [+|]NamedPermissions.enums.values; : : my Permissions $rwx = Read +| Write;# Fine : : which is still a little too constructive, too explicit (you have to get the : bit values right), as well as being too obscure for such a common task. : : : Of course, I could always create a macro to encapsulate the explicit : constructive obscurity: : : macro bitset ($typename, @value_names) : is parsed(/:s () '<' ( )+ '>' /) : { : # [build code to implement the above trick here] : } : : # and later... : : bitset Permissions < Read Write Exec >; : : but this is such a common requirement in engineering applications that it : would be great if this wheel didn't constantly have to be reinvented. : : : If anyone can think of a cleaner way to do it within the current semantics, : I'd be very happy to hear of it. I'm jetlagged and bleary from a full day of : teaching and I may well be missing an obvious answer. I think Sets could do this cleanly in the current design, given a little shove in the Pascal direction, but we could still perhaps do with a bit more syntactic and/or
Re: A common and useful thing that doesn't appear to be easy in Perl 6
First: what Damian said. Second: Whatever syntax people come up with has to make it easy and type-safe to name particular combinations of those bits. In other words, you should be able to make a bitset with Unix-style permissions: OTHER_EXECUTE OTHER_WRITE OTHER_READ GROUP_EXECUTE GROUP_WRITE GROUP_READ ... But still be able to make bitmasks (ignore the syntax here): OTHER_MASK = OTHER_READ +| OTHER_WRITE +| OTHER_EXECUTE; GROUP_MASK = GROUP_READ +| GROUP_WRITE +| GROUP_EXECUTE; ... These bitmasks should be properly typed with respect to the original bitset; which is to say, this should work: my Permissions $other_perms = $file_perms +& OTHER_MASK; -'f