There are three questions I don’t think we’re considering: * What does it mean to “partially count” an Enumerable that implements an “efficient” `count/1` function? * If such an Enumerable has side-effects for its `reduce/3` function, should they be somehow still happen even though the `count/1` doesn’t necessarily iterate the elements? * If such an Enumerable returns a larger count that asked for, should we return the larger “technically correct” value; or the `max + 1` value?
I generally like `count_until/2` because it‘s unopinionated about what you’re doing with the count. But the answers to the above question probably should be addressed and documented. I really see two ways to address the above question. Either we consider “count until implies actively counting” or “count until should take advantage of all optimizations and ignore side-effects”. My feel is that the latter is generally going to be more efficient in the common case but the former is less likely to create unexpected behavior from people who don’t know how their Enumerable is implemented. I’m inclined to favor the former. It won’t throw away efficiency that a custom Enumerable will implement, it’ll generally make naive code faster, and the rare cases where people expect side-effects is probably less important than either of those other benefits. Sent from my iPhone > On Dec 3, 2020, at 21:18, José Valim <jose.va...@dashbit.co> wrote: > > > Thanks Allen! I believe that's a good idea. > > I think the main insight is that we don't want a predicate function > (at_least? more_than?). Using compare returns three states - which is better > than two - but what if we just returned the number? After all, if I am > interested in knowing if something has less than 10, 10, or more than 10, I > just need to count until eleven. Returning a number seems to be more flexible > too. Therefore, what do you think about: count_until(enum, value)? > > To check if less, eq, or more than 10: > > case Enum.count_until(count, 10 + 1) do > 11 -> :gt > 10 -> :eq > _ -> :lt > end > > For at least 10: > > Enum.count_until(count, 10) == 10 > > For more than 10: > > Enum.count_until(count, 10 + 1) > 10 > > Thoughts? > > >> On Fri, Dec 4, 2020 at 2:14 AM Zach Daniel <zachary.s.dan...@gmail.com> >> wrote: >> Yep! I really like it :) >> >>> On Thu, Dec 3, 2020 at 7:52 PM eksperimental <eksperimen...@autistici.org> >>> wrote: >>> On Thu, 3 Dec 2020 19:06:18 -0500 >>> Allen Madsen <allen.c.mad...@gmail.com> wrote: >>> >>> > Enum.compare_count([], 1) #=> :lt >>> > Enum.compare_count([1], 1) #=> :eq >>> > Enum.compare_count([1, 2], 1) #=> :gt >>> >>> This is the way to go, because in one function call we can determine the >>> course of the action, such as in >>> >>> case Enum.compare_count(list, n) do >>> :lt -> ... >>> :eq -> ... >>> :gt -> ... >>> end >>> >>> when using the predicate functions it would require at least two >>> function calls. >>> >>> > >>> > Allen Madsen >>> > http://www.allenmadsen.com >>> > >>> > >>> > On Thu, Dec 3, 2020 at 6:51 PM Zach Daniel >>> > <zachary.s.dan...@gmail.com> wrote: >>> > >>> > > Well, List.count doesn’t exist yet, but either way it sounds like >>> > > not a great idea :) I couldn’t find examples in other Lang’s, so >>> > > maybe I’ll just throw out some other names: >>> > > >>> > > Enum.at_least?/2 >>> > > >>> > > Enum.at_most?/2 >>> > > >>> > > Enum.has_count?/2 >>> > > >>> > > On Thu, Dec 3, 2020 at 5:14 PM Michał Muskała <mic...@muskala.eu> >>> > > wrote: >>> > > >>> > >> Unfortunately this can’t be done automatically since it has subtle >>> > >> semantic differences. In particular Enum.count/1 (or length/1) not >>> > >> only traverses the list to count its size, but also verifies it’s >>> > >> a proper list raising an exception for improper lists. The >>> > >> difference could be seen for value like: >>> > >> >>> > >> >>> > >> >>> > >> [1, 2, 3 | :invalid] >>> > >> >>> > >> >>> > >> >>> > >> Calling length/1 or Enum.count/1 on this raises. If compiler did >>> > >> the optimisation you propose, for something like length(list) > 0, >>> > >> it wouldn’t fully traverse the list and wouldn’t raise. Thus such >>> > >> an optimisation is not possible in the general case. >>> > >> >>> > >> >>> > >> >>> > >> *From: *elixir-lang-core@googlegroups.com < >>> > >> elixir-lang-core@googlegroups.com> >>> > >> *Date: *Thursday, 3 December 2020 at 22:04 >>> > >> *To: *elixir-lang-core@googlegroups.com < >>> > >> elixir-lang-core@googlegroups.com> >>> > >> *Subject: *Re: [elixir-core:9802] Proposal `Enum.more_than?/2` or >>> > >> `List.more_than?/2` >>> > >> >>> > >> This probably off the table/unreasonable, but it also seems like >>> > >> something that could be statically solved and people would never >>> > >> need to know as it is just an optimization. E.g Enum.count(list) > >>> > >> n could optimized by the compiler? Probably wouldn’t be good for >>> > >> all Enums, since counting would be expected to enumerate them, so >>> > >> maybe only something like List.count 🤷♂️ >>> > >> >>> > >> >>> > >> >>> > >> On Thu, Dec 3, 2020 at 1:42 PM Zach Daniel >>> > >> <zachary.s.dan...@gmail.com> wrote: >>> > >> >>> > >> Another benefit to the options list would be supporting it for >>> > >> count with a predicate, e.g Enum.count(enum, &some_predicate/1, >>> > >> max: 4) >>> > >> >>> > >> >>> > >> >>> > >> On Thu, Dec 3, 2020 at 1:35 PM Zach Daniel >>> > >> <zachary.s.dan...@gmail.com> wrote: >>> > >> >>> > >> Nothing is jumping out at me from elsewhere yet, but another >>> > >> option might be accepting options in `Enum.count`, like >>> > >> `Enum.count(list, max: 4)`. I’ll keep searching though. >>> > >> >>> > >> >>> > >> >>> > >> On Thu, Dec 3, 2020 at 1:31 PM Zach Daniel >>> > >> <zachary.s.dan...@gmail.com> wrote: >>> > >> >>> > >> I agree on the name feeling subpar :) I’ll take a look and see if >>> > >> I can find other examples. >>> > >> >>> > >> >>> > >> >>> > >> On Thu, Dec 3, 2020 at 12:21 PM José Valim <jose.va...@dashbit.co> >>> > >> wrote: >>> > >> >>> > >> Thanks Zach! I like this idea but the proposed name, for some >>> > >> reason, doesn't sit right with me. Is there any prior art from >>> > >> other langs we could look at? >>> > >> >>> > >> >>> > >> >>> > >> On Thu, Dec 3, 2020 at 6:15 PM Zachary Daniel >>> > >> <zachary.s.dan...@gmail.com> wrote: >>> > >> >>> > >> Counting a list, especially a large one, to know if there are >>> > >> "more than x" or "less than x" items is inefficient. >>> > >> >>> > >> >>> > >> >>> > >> Right now I often see things like `if Enum.count(list) > 4 ...`, >>> > >> mostly because writing a recursive `more_than?` check is tedious, >>> > >> or doing something like `Enum.empty?(Enum.drop(list, 4))` is not >>> > >> very expressive. >>> > >> >>> > >> >>> > >> >>> > >> I think it would be nice to have an `Enum.more_than?` that does >>> > >> that work for you. It could also be `List.more_than?/2` if we >>> > >> don't want it in Enum. Any thoughts? >>> > >> >>> > >> -- >>> > >> You received this message because you are subscribed to the Google >>> > >> Groups "elixir-lang-core" group. >>> > >> To unsubscribe from this group and stop receiving emails from it, >>> > >> send an email to elixir-lang-core+unsubscr...@googlegroups.com. >>> > >> To view this discussion on the web visit >>> > >> https://groups.google.com/d/msgid/elixir-lang-core/263d7c39-a32b-4294-93d8-40f248c9b3c8n%40googlegroups.com >>> > >> <https://groups.google.com/d/msgid/elixir-lang-core/263d7c39-a32b-4294-93d8-40f248c9b3c8n%40googlegroups.com?utm_medium=email&utm_source=footer> >>> > >> . >>> > >> >>> > >> -- >>> > >> You received this message because you are subscribed to the Google >>> > >> Groups "elixir-lang-core" group. >>> > >> To unsubscribe from this group and stop receiving emails from it, >>> > >> send an email to elixir-lang-core+unsubscr...@googlegroups.com. >>> > >> To view this discussion on the web visit >>> > >> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4JX4NE1yWH1G5L_DjF18v8zejF0%2BSkb_oz%3DPiUHM8Mz1w%40mail.gmail.com >>> > >> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4JX4NE1yWH1G5L_DjF18v8zejF0%2BSkb_oz%3DPiUHM8Mz1w%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> > >> . >>> > >> >>> > >> -- >>> > >> You received this message because you are subscribed to the Google >>> > >> Groups "elixir-lang-core" group. >>> > >> To unsubscribe from this group and stop receiving emails from it, >>> > >> send an email to elixir-lang-core+unsubscr...@googlegroups.com. >>> > >> >>> > >> To view this discussion on the web visit >>> > >> https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0BBGCrgbZamFs%2BeqLUis6mFQgvUHkKK1htSN5rDDWwMRQ%40mail.gmail.com >>> > >> <https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0BBGCrgbZamFs%2BeqLUis6mFQgvUHkKK1htSN5rDDWwMRQ%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> > >> . >>> > >> >>> > >> -- >>> > >> You received this message because you are subscribed to the Google >>> > >> Groups "elixir-lang-core" group. >>> > >> To unsubscribe from this group and stop receiving emails from it, >>> > >> send an email to elixir-lang-core+unsubscr...@googlegroups.com. >>> > >> To view this discussion on the web visit >>> > >> https://groups.google.com/d/msgid/elixir-lang-core/DB7PR07MB3899C92933992464F17898E1FAF20%40DB7PR07MB3899.eurprd07.prod.outlook.com >>> > >> <https://groups.google.com/d/msgid/elixir-lang-core/DB7PR07MB3899C92933992464F17898E1FAF20%40DB7PR07MB3899.eurprd07.prod.outlook.com?utm_medium=email&utm_source=footer> >>> > >> . >>> > >> >>> > > -- >>> > > You received this message because you are subscribed to the Google >>> > > Groups "elixir-lang-core" group. >>> > > To unsubscribe from this group and stop receiving emails from it, >>> > > send an email to elixir-lang-core+unsubscr...@googlegroups.com. >>> > > To view this discussion on the web visit >>> > > https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0BO2QESHcaL7-svOoAGqvr6hJi%3D8AHFqi-qNZdoFEMMwA%40mail.gmail.com >>> > > <https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0BO2QESHcaL7-svOoAGqvr6hJi%3D8AHFqi-qNZdoFEMMwA%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> > > . >>> > > >>> > >>> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "elixir-lang-core" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to elixir-lang-core+unsubscr...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/elixir-lang-core/5fc98859.1c69fb81.3cf33.11a4SMTPIN_ADDED_MISSING%40gmr-mx.google.com. >> >> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to elixir-lang-core+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/CAK-yb0AfjLS-vef8u9EWpuQ3tHVaXXfvAF9QMu%2B9hin7WjoNQA%40mail.gmail.com. > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to elixir-lang-core+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4LNUYuR%2BztiJ5p3viSEd-Tj6CbptUvyt9CrGigRtKjTMQ%40mail.gmail.com. -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/1B141347-7013-4C56-BCFB-E1A1A4430422%40brex.com.