Reputation:
I created a tuple type in Javascript that implements the Iterable
protocol. Now it should be easy to convert to Map
:
const Tuple = (...args) => {
const Tuple = f => f(...args);
Tuple[Symbol.iterator] = () => args[Symbol.iterator]();
return Tuple;
};
new Map([Tuple(1, "a"), Tuple(2, "b")]); // Map {undefined => undefined}
Instead I have to do the conversion manually:
const Tuple = (...args) => {
const Tuple = f => f(...args);
Tuple[Symbol.iterator] = () => args[Symbol.iterator]();
return Tuple;
};
const toArray = tx => tx((...args) => args);
const Map_ = (...pairs) => {
return new Map(pairs.map(pair => toArray(pair)));
};
const map = Map_(Tuple(1, "a"), Tuple(2, "b"));
console.log(map.get(1), map.get(2)); // "a" "b"
It seems as if Map
only accepts an Iterable
for the outer composite type, not for the inner pairs. What am I missing? Is there another way to achieve the conversion?
Upvotes: 3
Views: 490
Reputation: 664307
I created a tuple type in Javascript that implements the
Iterable
protocol.
Don't. Tuples have the distinct property that they are of fixed length and every element has (can have) its own type, whereas (iterable) collections consist of multiple elements of the same type. Of course JavaScript doesn't care about types (all arrays are heterogeneous), but you as a programmer should.
Why does
Map
only accept anIterable
for the outer composite type, not for the inner pairs?
For the exact same reason. The elements are pairs, or two-tuples, represented as arrays (for lack of another data structure, and simplicity of not having to introduce one like they did for iterator results). They always have exactly two elements, accessible as [0]
and [1]
(they don't even need a .length
!), and there is absolutely no reason iterate them.
Upvotes: 0
Reputation: 1
const Tuple = (...args) => Object.entries({[args.shift()]: args.shift()});
const map = new Map(Tuple(0, "a").concat(Tuple(1, "b")));
console.log(map.get("0"), map.get("1"));
Upvotes: -2
Reputation: 1074148
Map
's constructor is defined as accepting any Iterable of key/value objects, where the key/value objects are defined as objects where property 0
is the key and property 1
is the value. It says nothing about allowing Iterables for the key/value objects. (It might have been cool if it did allow them and define that it would call the iterator exactly twice, but...that's not what they did. :-) And it would be more complex...)
If we look at the spec, your Tuple
would work if it supported the properties 0
(for the key) and 1
(for the value). For instance:
// (Defined this way because you seemed to want a non-constructor)
const TupleMethods = {
get "0"() {
return this.key;
},
get "1"() {
return this.value;
}
};
const Tuple = (key, value) => {
const t = Object.create(TupleMethods);
t.key = key;
t.value = value;
return t;
}
// Usage:
const m = new Map([
Tuple("one", "uno"),
Tuple("two", "due"),
Tuple("three", "tre")
]);
console.log(m.get("two")); // "due"
In a comment you mentioned immutability. Perhaps:
// (Defined this way because you seemed to want a non-constructor)
const TupleMethods = {};
Object.defineProperties(TupleMethods, {
"0": {
get() {
return this.key;
}
},
"1": {
get() {
return this.value;
}
}
});
const Tuple = (key, value) => {
const t = Object.create(TupleMethods);
Object.defineProperties(t, {
key: {
value: key
},
value: {
value: value
}
});
return t;
};
// Usage:
const m = new Map([
Tuple("one", "uno"),
Tuple("two", "due"),
Tuple("three", "tre")
]);
console.log(m.get("two")); // "due"
Upvotes: 4