Bug 7957 – std.functional untuple/untupleReversed too

Status
RESOLVED
Resolution
WONTFIX
Severity
enhancement
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-04-20T18:08:34Z
Last change time
2017-10-15T14:27:46Z
Assigned to
RazvanN
Creator
bearophile_hugs

Comments

Comment #0 by bearophile_hugs — 2012-04-20T18:08:34Z
I suggest two functions like this in Phobos. Maybe a more correct name for them is apply/applyReversed, but apply() is probably meant to be more flexible. The purpose of untuple is to apply the items of a tuple as arguments to a function, inside map/filter. So instead of this: t => foo2(t.tupleof) You write a less complex: untuple!foo2 Python has the itertools.starmap function to perform a lazy map with untuple (apply) too, but it lacks a starfilter: http://docs.python.org/library/itertools.html#itertools.starmap untupleReversed does a little more, because it also reverses the tuple items before feeding them to the foo2 function. This is often useful for 2-tuples, it's related to (but not the same as) the "flip" function used in Haskell: -- | @'flip' f@ takes its (first) two arguments in the reverse order of @f@. flip :: (a -> b -> c) -> b -> a -> c flip f x y = f y x It's an "adapter" between a range of tuples and an already written function that takes flipped or reversed arguments. - - - - - - - - - - - - - - - - - - - - - - - - - - - - import std.algorithm, std.range, std.stdio, std.functional, std.typecons, std.traits; // To apply a given callable to a Tuple (alternative name: "apply"). template untuple(alias callable) { auto untuple(Tup)(Tup t) if (isTuple!Tup && ParameterTypeTuple!callable.length == Tup.length) { return callable(t.tupleof); } } void main() { auto a1 = "abcd"d; auto a2 = [10, 20, 30, 40]; auto a3 = [100, 200, 300, 400]; static int foo2(dchar a, int b) { return a + b; } zip(a1, a2).map!(t => foo2(t.tupleof))().writeln(); zip(a1, a2).map!(untuple!foo2)().writeln(); static int foo3(dchar a, int b, int c) { return a + b + c; } zip(a1, a2, a3).map!(untuple!foo3)().writeln(); } Output: [107, 118, 129, 140] [107, 118, 129, 140] [207, 318, 429, 540] - - - - - - - - - - - - - - - - - - - - - - - - - - - - One version that also reverses the tuple items: import std.algorithm, std.range, std.stdio, std.typecons, std.traits, std.typetuple, std.string, std.conv; // _genIndexes("foo", 3) ==> "foo[2], foo[1], foo[0]" private string _genIndexes(string name, size_t start) { string[] result; for (int i = start - 1; i >= 0; i--) result ~= name ~ "[" ~ text(i) ~ "]"; return result.join(", "); } // To apply a given callable to a Tuple (alternative name: "apply"), // but flipping the tuple items. template untupleReversed(alias callable) { auto untupleReversed(Tup)(Tup t) if (isTuple!Tup && ParameterTypeTuple!callable.length == Tup.length) { mixin("return callable(" ~ _genIndexes("t", Tup.length) ~ ");"); } } void main() { auto pairs = zip([10, 20, 30, 40], [100, 200, 300, 400]); static int div2(int a, int b) { return a / b; } pairs.map!(t => div2(t[1], t[0]))().writeln(); pairs.map!(untupleReversed!div2)().writeln(); } Output: [10, 10, 10, 10] [10, 10, 10, 10]
Comment #1 by razvan.nitu1305 — 2017-10-13T09:12:31Z
Comment #2 by andrei — 2017-10-15T14:27:46Z
Per the discussion in the PR this idiom seems to be less frequent in D than Python.