Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

features of and declaring Mapping|Set|Hash values|variables

4 views
Skip to first unread message

Darren Duncan

unread,
Jun 29, 2006, 7:24:20 PM6/29/06
to perl6-l...@perl.org
Lately I've been wanting to cross-apply features of the Set type to
the Mapping type, as well as of the Hash type to both of those, as I
see all of these as being very similar to each other conceptually and
in some cases interchangeable.

1. Looking at the language in Synopsis 6 for data types, I see:

Set Unordered Seqs that allow no duplicates
Junction Sets with additional behaviours
Pair Seq of two elements that serves as an one-element Mapping
Mapping Pairs with no duplicate keys

I would like to know if Mapping.does(Set) and whether I could use the
full range of Set operators on them, as I would like to do?

My impression is that it be reasonable to define a generic Mapping as
being a Set whose elements are all constrained to be Pairs, and
further that all keys of those pairs are distinct; eg:

subset Mapping of Set where {
all(.members).does(Pair) and +all(.members.map:{.key}) == +all(.members)
};

If this is true, then I suggest rewording the above line in Synopsis
6 to better clarify the situation, like this:

Mapping Set of Pairs that allow no duplicate Pair keys

It would be very useful to employ Set operations like subset() or
union() or difference() etc on Mappings, that return Mappings. With
such binary operators, each Mapping element has to match entirely as
a whole Pair, having both the same key and same value. In the case
of union(), if any source Pairs have the same keys but different
values, the union() would fail due to the unique key constraint, with
similar force to dividing by zero in a non-NaN setting.

2. Similarly, I would like to know if Hash.does(Mapping) and so that
we can therefore use all the Set and Mapping operators on Hashes, but
that their output is Hashes. Likewise very useful.

3. I missed the syntax for declaring anonymous Set or Mapping in the
Synopsis. Has it been defined yet?

Something that is distinct from:

[1,2] # Array
(1,2) # Seq
{1=>2,3=>4} # Hash
(1=>2) # Pair in positional context
1=>2 # Pair in named context
all(1,2,3) # Junction

Eg, do we need to use keywords:

set(1,2,3)
mapping(1=>2,3=>4)

Or can this be accomplished without such keywords?

I am assuming we don't have to invoke some new() because these are
built-in basic types.

4. Since they are already known to be unique, is it possible to get
an actual Set returned when invoking something akin to .keys or
.pairs or a Mapping or Hash? Or do we need to always construct such
ourself by wrapping the call with a set() or all(), in order to use
set operations on them? Would the latter case be inefficient or
verbose?

5. I'm wondering about syntax for using Sets like Junctions. Eg, if
I want to see if one set is a proper subset of another, can I say
this:

all($s1) === any($s2)

Or do I have to rewrap their members into explicit Junctions first like this:

all($s1.members) === any($s2.members)

I am ignoring for the moment that Set probably declares named
operators that let me do this:

$s2.subset($s1)

I don't want to have to use the second syntax if I don't have to,
since I like consistency with Junction syntax.

The same questions apply to using Mappings and Hashes as Sets.

6. From on my readings of Synopsis 6,9,12, it looks like you can
declare a Hash whose keys are restricted to non-empty strings like
this:

subset FooName of Str where { $^n ne '' };
subset FooHash of Hash{FooName} of Bar;

or

subset FooHash of Hash{Str where { $^n ne '' }} of Bar;

Then if you declare a variable or routine parameter of type FooHash,
someone can assign/pass only a Hash value to it whose keys are all
non-empty strings.

So is that a reasonable interpretation?

7. If so, then can I use the same syntax with a Mapping, which looks
like a Hash but that it is immutable; eg:

subset FooMap of Mapping{FooName} of Bar;

Then if you declare a variable or routine parameter of type FooMap,
someone can assign/pass only a Mapping value to it whose keys are all
non-empty strings.

8. Similar question but with a Set:

subset FooSet of Set{FooName};

Will this work to make a Set that can only have non-empty strings as members?

9. If you declare a parameter of a type that does Foo, and you pass
an argument that is a different type that does Foo, but neither of
them is of type Foo, will the compiler accept the binding (though it
may fail at runtime)?

Thanks. -- Darren Duncan

Sam Vilain

unread,
Jun 29, 2006, 9:25:17 PM6/29/06
to Darren Duncan, perl6-l...@perl.org
Darren Duncan wrote:
> 1. Looking at the language in Synopsis 6 for data types, I see:
>
> Set Unordered Seqs that allow no duplicates
> Junction Sets with additional behaviours
> Pair Seq of two elements that serves as an one-element Mapping
> Mapping Pairs with no duplicate keys
>
> I would like to know if Mapping.does(Set) and whether I could use the
> full range of Set operators on them, as I would like to do?
>
> My impression is that it be reasonable to define a generic Mapping as
> being a Set whose elements are all constrained to be Pairs, and
> further that all keys of those pairs are distinct; eg:
>
> subset Mapping of Set where {
> all(.members).does(Pair) and +all(.members.map:{.key}) == +all(.members)
> };
>

Hmm. I still think a more generic Collection makes this more correct.

subset Set of Collection where {
all(.members) =:= one(.members);
}

subset Mapping of Collection where {
all(.members).does(Pair) and
all(.members).key =:= one(.members).key;
}

ie, being a Set is introducing a constraint, which is then duplicated in
the Mapping type. Now, you could argue that the Set constraint is
"shadowed" by the Mapping constraint and the constraints analysis system
could prove it does not need to be applied, but that's quite a high
level thing to expect the compiler to do at this point, I think.

However the above definitions, in my opinion, miss the potential of
parametric roles.

> If this is true, then I suggest rewording the above line in Synopsis
> 6 to better clarify the situation, like this:
>
> Mapping Set of Pairs that allow no duplicate Pair keys
>
> It would be very useful to employ Set operations like subset() or
> union() or difference() etc on Mappings, that return Mappings.
>

> 2. Similarly, I would like to know if Hash.does(Mapping) and so that
> we can therefore use all the Set and Mapping operators on Hashes, but
> that their output is Hashes. Likewise very useful.
>

How about;

Mapping Collection of Pairs that allow no duplicate Pair keys.

If "Collection" is parametric it must be a role, which means that we
can't directly subset it; we use role composition instead (I'm assuming
that we can use where{} during role composition).

role Set of Collection[Item] where { all(.members) =:= one(.members) };

# one of these
role Mapping of Collection[Pair] where {
all(.members).key =:= one(.members).key
};

# what is a pair, anyway?
role Pair of Seq[Item,Item] {
method key of Item { &.item(0) }
method value of Item { &.item(1) }
};

role HEK of Seq[Str, Item] does Pair;

role Hash of Collection[HEK] does Mapping;

role ArrayItem of Seq[Int, Item] {
method index of Int { &.item(0) }
method value of Item { &.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;
}
}

There are some problems with the above, notably "Pair" could be
parametric, and the Array post_circumfix method should be an lvalue return.

I'm terribly sorry I haven't dedicated more time to developing this into
a working prototype module for Perl 5. RSN I hope.

> 3. I missed the syntax for declaring anonymous Set or Mapping in the
> Synopsis. Has it been defined yet?
>
> Something that is distinct from:
>
> [1,2] # Array
> (1,2) # Seq
> {1=>2,3=>4} # Hash
> (1=>2) # Pair in positional context
> 1=>2 # Pair in named context
> all(1,2,3) # Junction
>
> Eg, do we need to use keywords:
>
> set(1,2,3)
> mapping(1=>2,3=>4)
>
> Or can this be accomplished without such keywords?
>
> I am assuming we don't have to invoke some new() because these are
> built-in basic types.
>

I don't see a problem with .new() for these types, which some might
consider arcane.

set() doesn't work for the Perl 5 prototypes, too many modules want to
use $object->set().

Users who want a shorthand can use a module that lets them write ⟦ ⟧ etc
(say).

> 4. Since they are already known to be unique, is it possible to get
> an actual Set returned when invoking something akin to .keys or
> .pairs or a Mapping or Hash? Or do we need to always construct such
> ourself by wrapping the call with a set() or all(), in order to use
> set operations on them? Would the latter case be inefficient or
> verbose?
>

Interesting idea. I guess that there are many places where a list or
array type is specified where it should be a set.

> 5. I'm wondering about syntax for using Sets like Junctions. Eg, if
> I want to see if one set is a proper subset of another, can I say
> this:
>
> all($s1) === any($s2)
>
> Or do I have to rewrap their members into explicit Junctions first like this:
>
> all($s1.members) === any($s2.members)
>
> I am ignoring for the moment that Set probably declares named
> operators that let me do this:
>
> $s2.subset($s1)
>
> I don't want to have to use the second syntax if I don't have to,
> since I like consistency with Junction syntax.
>
> The same questions apply to using Mappings and Hashes as Sets.
>

Good questions. Do we have a splat method?

> 6. From on my readings of Synopsis 6,9,12, it looks like you can
> declare a Hash whose keys are restricted to non-empty strings like
> this:
>
> subset FooName of Str where { $^n ne '' };
> subset FooHash of Hash{FooName} of Bar;
>
> or
>
> subset FooHash of Hash{Str where { $^n ne '' }} of Bar;
>

Hmm, I don't think subset is right for parametric roles..

> Then if you declare a variable or routine parameter of type FooHash,
> someone can assign/pass only a Hash value to it whose keys are all
> non-empty strings.
>
> So is that a reasonable interpretation?
>
> 7. If so, then can I use the same syntax with a Mapping, which looks
> like a Hash but that it is immutable; eg:
>
> subset FooMap of Mapping{FooName} of Bar;
>
> Then if you declare a variable or routine parameter of type FooMap,
> someone can assign/pass only a Mapping value to it whose keys are all
> non-empty strings.
>

I currently see two distinct ways to do this; subset Mapping, please add
sugar to taste:

subset FooMap of Mapping where {
$?CLASS.meta.get_role("Mapping").#< what's a long dot? >
.get_role("Collection").get_role("Pair").parameters
~~ (FooName, Bar)
}

or role composition:

role FooMap of Collection[Seq[FooName,Bar]] does Mapping;

The "Mapping" class should probably allow you to just use:

role FooMap of Mapping[FooName, Bar];


> 8. Similar question but with a Set:
>
> subset FooSet of Set{FooName};
>
> Will this work to make a Set that can only have non-empty strings as members?
>
> 9. If you declare a parameter of a type that does Foo, and you pass
> an argument that is a different type that does Foo, but neither of
> them is of type Foo, will the compiler accept the binding (though it
> may fail at runtime)?
>

I'll punt on that one.

Sam.

0 new messages