-
Notifications
You must be signed in to change notification settings - Fork 292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
List method flatmap is inappropriately discouraged #1428
Comments
Please see RT #130520 and say if you still think that the warning should be removed :) Maybe to resolve this issue we should simply add a link to the ticket. |
Basically So there is only few possible reasons to keep it:
Perhaps there are other reasons I'm not thinking of, but it seems the main reason to keep it is that it exists. If it didn't exist already, it would not be an accepted addition to the language. This is just a quick summary of arguments against it in RT #130520 |
It is being used in some modules, but very likely some of these cases are old, bit-rotted and were relying on pre-glr behavior. In theory we can wipe out its usage with less than 30 pull requests. Actual users are unlikely to use it because the documentation says not to. |
Note that the two alternatives you provide aren't equivalent, which is I think the core issue with
Here's a more destructive example, considering
|
I listed |
Cool. i think we can close this issue if we change the docs to say that it will be deprecated in 6.d (instead of saying that flatmap is a bad practice). It may be too early for that, but still.
But they are? |
Ah, I misread the second one wasn't a method chain. |
I think it's really bad decision to deprecate it. It's one of the 2 operations needed for defining monad (it's also known as "bind' or ">>=" in haskell) and is common name in a lot of languages (even Java has it nowdays). Yes it can be replaced with map().flat but this comes at the cost of another container allocation and breaking expectations. |
@luben what container allocation? Can you clarify? And also, what expectations? |
Wouldn't shesh optimize that away? And in any case, at least the current rakudo implementation does just that; two method calls.
But that's the key issue with the method. There's no easy-to-discern expectation. |
Regarding the allocation, Even if spesh starts optimizing this combination of method calls over lists I don't expect it to be able to do the same in the generic case. Regarding the expectations of people coming from other languages, |
[flatmap is] one of the 2 operations needed for defining monad (it's
also known as "bind' or ">>=" in haskell)
Sort of.
flatmap does not apply to monads in general, as Monad itself does not
give you access to the elements that went into the composition so you
cannot flatmap over them.
List happens to be a Monad, and List's flatmap happens to implement >>=,
so for List and subtypes the statement is true. (Except in Haskell I
think - List implements Monad in two different ways I hear.)
Regarding the allocation, |m.map(f).flat| decomposes into |{ tmp c =
m.map(f); tmp.flat }|, so the |tmp| is new container allocation that
is avoided by |flatmap|.
Even if spesh starts optimizing this combination of method calls
over lists I don't expect it to be able to do the same in the
generic case.
As long as flat() returns a list the optimization is going to work.
If people know that intermediate lists are optimized away, they will
start to prefer lists over other data structures. (I know for sure that
this happened in the Haskell community.)
Regarding the expectations of people coming from other languages,
|flatmap| is common name, e.g. java, scala, swift, JS functional
libraries, etc.
http://reactivex.io/documentation/operators/flatmap.html has an overview
(look at the end, where it maps ReactiveX' flatmap concept to functions
in various languages).
Most languages indeed name it "flat map", with the understanding that
flatmap(x) is equivalent to flat(map(x)).
|
@AlexDaniel I'll take a look at the modules I'm in control of. I've just altered https://github.com/jonathanstowe/Chronic and will take a look at https://github.com/sergot/http-useragent this evening, so on my part I'm for it. |
I don't think we create any temporary containers to store intermediary results.
I was talking about the generic case and I think rakudo implementation already does it. But even if it didn't, we're not adding a whole 'nuther method to the language for a theoretical saving of a single container allocation in implementation X. |
I don't know much about this, so bear with me, but… You've been talking about intermediate lists and things getting optimized away, but I don't really see how this corresponds to what we have. Both map and flat return a Seq, so why would there be any temporary list? Is there any case when this actually happens? For example: ({my $x = ++$; say “generate $x”; $x} … ∞).map({say “map $_”; $_ + 1}).flat[^5].say Result:
|
There is no way that If it can be made to be significantly faster, we can add a So if Basically just because it is a good idea in Haskell doesn't mean it is a good idea in Perl 6. |
Basically just because it is a good idea in Haskell doesn't mean it is a
good idea in Perl 6.
I agree that efficiency is probably not the most interesting point here.
The commonality among other languages with strong list/sequence and
functional support is more convincing (to me anyway).
Particularly if I see libraries reinvent that particular wheel.
Even more so if it is being reinvented under different names, as the
ReactiveX page seems to indicate. If it's going to be reinvented, then
it's better if is has a common name and associated semantics.
|
Different names, syntaxes, and conventions are ideal in different languages. Larry Wall has repeatedly talked about regretting certain C-isms that he had to put in Perl, in order for the language to not be rejected by the programming community of that time as "insufficiently C-like". Let's compare
TL;DR: PS: People who want to code in Perl 6 as if it was Haskell, can simply write
|
@smls I'd usually agree, but you forgot an important benefit: From that derives: So the picture is clear if and only if we ignore some benefits. There's also the following harm: I don't find any of the arguments overly compelling, except the one that flatmap seems to be so universally used that people even reinvent it. |
P.S. I hope I made it clear that I'm definitely not after writing Haskell in Perl6. |
From a certain viewpoint we already have it, except with a space. my @a = flat map *.name, @b
This is not a good argument, we renamed
Apparently you don't realize this is almost an excellent reason to remove it. Anybody could come along and add a Actually that is even more reason to remove it, it is currently taking up a method name that a class author might want to use for something else one day. (minor point) One of the goals in the design of Perl 6 is that it is worse to confuse an expert than a neophyte. I've been programming almost exclusively in Perl 6 for so long that I basically have to translate other languages into it in order to understand them. I was confused when I first saw Also note that removing it couldn't confuse a neophyte, except insofar as they might be confused why it isn't there. Even then they could only be confused if they came from one of the languages that has it. About the only reasons for keeping it are:
Reasons to remove it:
About that last one, note that to get something that has similar memory usage to Haskell's my $sum = [\+]( 1..10 ).tail;
# (1, 3, 6, 10, 15, 21, 28, 36, 45, 55).Seq.tail or to get closer to how it would work in Haskell multi curry-add ( &c, $head ){
-> &prev, $next { prev +$head + $next }.assuming( &c )
}
multi curry-add ( $head, $second ){
-> $next { $head + $second + $next}
}
my $sum = [[&curry-add]]( 1..10 ).(0); Rather than: my $sum = [+] 1..10; I can only assume that other purely functional languages would have similar disparities with how Perl 6 works with lists. |
OK folks, this discussion is awesome, right. But in terms of a doc ticket, there's nothing to be done here. We have an RFC ticket to toss it out, so discouraging flatmap is appropriate, especially considering that I'll change the wording a little bit and close the ticket. Feel free to continue your discussion on https://rt.perl.org/Ticket/Display.html?id=130520 (if it is ever decided that this RFC is rejected, we can remove the discouraging message from the docs). |
Feel free to reopen and continue discussion here, but please stay on topic (i.e. “we should not discourage the use of a feature that is strongly RFC-ed for removal because …”). |
The file
List.pod6
contains some relatively new verbiage which discourages the use of theflatmap
method in favor of callingmap
followed byflat
. Usingflatmap
is called "bad practice" and "confusing." But flat-mapping is a common technique in many programming languages, and there seems to be no particular reason to avoid in in Perl 6. Therefore, I would request that this warning be removed.The text was updated successfully, but these errors were encountered: