On Tue, Feb 4, 2020 at 10:04 AM Ben Wilson <benwilson...@gmail.com> wrote:
> > The code Function.constant(c) is much more expressive and descriptive > than fn _ -> c end. > > To be clear, if this could work without macros, I'd be inclined to agree, > although I recognize that there may be some who do not. My issue personally > is that there simply isn't any function you can write that will behave this > way, for all values of `c`. You could build `constant` as a macro, but I > think that ends up killing the whole "name a concept" thing, because really > the dominant concept at hand ends up being how macros work. > I don’t really have a strong opinion on this proposal, but I do think that this could be done without macros and if naming a concept is important then it’s worth considering. I do see one problem with `Function.constant/1` in how it would be applied, because there would potentially need to be some magic involved (which brings it back to possible macros). The simplest implementation would be: def constant(const), do: fn -> const end That will work well for `Stream.repeatedly/1` as the function parameter is `/0`, but not so well for `Enum.map/2` as the function parameter is `/1`. This could be addressed with multiple functions (constant1/1, etc.) or with an arity parameter (both examples shown below): def constant(const), do: fn -> const end def constant1(const), do: fn _ -> const end # OR def constant(const, arity \\ 0) def constant(const, 0), do: fn -> const end def constant(const, 1), do: fn _ -> const end I’m not sure it would be possible to know, at the call-site, whether you needed a `/0` or `/1` anonymous function through macros, and I’m not sure that it would be meaningful to have constant for _larger_ than `/{0,1}` functions. But I do know that I have occasionally wanted to write: Enum.map([0, 1, 2], &:padding) # or any other non-function value and have it act as the correct type of function. -a > On Tuesday, February 4, 2020 at 9:39:48 AM UTC-5, Bruce Tate wrote: >> >> Thanks for the discussion, all. I enjoy being here. >> >> *Summary: I will bow out of this conversation after this one last >> attempt. Feel free to skip it. * >> >> I will say that I would use this function frequently in my teaching and >> in my day-to-day code if I had it. I think it describes a concept that is >> well known in math, and useful in any functional language. For example, >> resetting a counter in an agent or genserver with a similar API. Creating a >> stream of constants as padding/initialization data of arbitrary length >> (with take later). >> >> > we'll bloat the language. >> >> I don't think this is a good argument for foundational concepts. A >> library that provides names for significant functions in math and >> programming is important enough. >> >> > I’d argue back that this particular pattern, where you want a list of >> fixed length with the same value, is much better served by >> `List.duplicate/2`. >> >> Maybe. But List.duplicate/2 doesn't really solve the same problem. >> Stream.repeatedly with Function.constant gives me padding of an arbitrary >> length, that I can then later instantiate based on the number of columns >> that I need. It's a great pattern. It's basically fixed vs variable. >> >> > if I know anonymous functions, I know what’s going on. >> >> Variables, anonymous functions, and the like are not equivalent. A >> library function has weight and descriptive ability that writing code just >> doesn't. I can tell you that `fn(x) -> x end` and `Function.identity` are >> not remotely equivalent when it comes to scanning code. There's a cost to >> that much syntax. >> >> I'll say one more thing before moving on from this conversation. >> >> Naming concepts in code is important. The code Function.constant(c) is >> much more expressive and descriptive than fn _ -> c end. It gives us a >> common language across programming languages and theory plus math to >> express ideas. We in the Elixir community often undersell the idea, and we >> pay in the idioms that new coders must learn to be successful with our >> language. >> >> *So thanks to all for a great discussion. I do recognize there's no >> appetite for these ideas in Elixir, so I'll gracefully bow out. * >> >> -bt >> >> >> >> On Tue, Feb 4, 2020 at 8:58 AM Amos King <am...@binarynoggin.com> wrote: >> >>> Ben, >>> >>> That is how const is used in Haskell. Although without currying I don’t >>> see how it is useful. I’m waiting to see an example that drives it home. I >>> agree with Bruce about naming concepts but I don’t see the concept as >>> useful in Elixir. >>> >>> Bruce, do you have a code sample using the idea? >>> >>> Amos King >>> CEO >>> Binary Noggin >>> >>> On Feb 4, 2020, at 07:35, Ben Wilson <benwil...@gmail.com> wrote: >>> >>> >>> Addendum: I re-read the proposal because the const/1 vs const/2 thing >>> confused me, and I'm seeing both in play there. The spec is arity 2, the >>> example right after though is arity 1, and the Enum example is arity 2 but >>> without a constant value. The Enum example perhaps makes the most sense, >>> because you could do: >>> >>> ``` >>> Enum.map([1,2,3,4], &const(&1, :foo)) >>> ``` >>> which would return `[:foo, :foo, :foo, :foo]` effectively replacing the >>> contents of the list with all `:foo`. Is that the idea? >>> >>> On Tuesday, February 4, 2020 at 8:16:53 AM UTC-5, Ben Wilson wrote: >>>> >>>> I agree with Michal. Additionally, I'm not clear how `const/1` could be >>>> used in Bruce's example at all. >>>> >>>> To elaborate, `fn -> foo() end` and `const(foo())` cannot be >>>> equivalent when `const/1` is merely a function. This becomes readily >>>> apparent when `foo()` is side effects or side causes. In the first case, >>>> `foo()` is never evaluated until the wrapping function is called, in the >>>> case of `const/1` however the function is evaluated and then its return >>>> value bound over by a function. Eg: `fn -> DateTime.utc_now() end` will >>>> always return the current time when evaluated, where as >>>> `const(DateTime.utc_now())` will evaluate the current time once and then >>>> always return that same time. >>>> >>>> That might sound useful, except that we already can do that by simply >>>> binding the return value of `DateTime.utc_now()` to a variable and passing >>>> that variable around. I'm having difficulty coming up with a scenario >>>> where, instead of simply having the value, I have the value wrapped in an >>>> anonymous function that I need to call. >>>> >>>> Consequently, I struggle to see where `const/1` can actually be used, >>>> or how it would work. In the example in the initial proposal, there is >>>> this: >>>> >>>> ``` >>>> Enum.map([0,1,2,3], &Function.const/2) >>>> ``` >>>> >>>> As a minor note, presumably that should be `const/1`, right? More >>>> importantly, what is the return value here? If it's `[0, 1, 2, 3]` then >>>> `const/1` is equivalent to `identity`. If it's >>>> >>>> ``` >>>> [fn -> 1 end, fn -> 2 end, fn -> 3 end, fn -> 4 end] >>>> ``` >>>> >>>> then a simple list of integers seems universally more useful. >>>> >>>> On Tuesday, February 4, 2020 at 5:03:39 AM UTC-5, Michał Muskała wrote: >>>>> >>>>> I’d argue back that this particular pattern, where you want a list of >>>>> fixed length with the same value, is much better served by >>>>> `List.duplicate/2`. >>>>> >>>>> >>>>> >>>>> I think in general, higher order combinator functions like identity, >>>>> const, flip, and friends are usually used to facilitate the point-free >>>>> style of programming in languages like Haskell. And in general point-free >>>>> style usually does not lead to the most readable code. >>>>> >>>>> >>>>> >>>>> Again, referring to the example provided, if I know anonymous >>>>> functions, I know what’s going on. When using `Funcion.const`, I have to >>>>> understand that concept as well. There’s one extra thing to learn. >>>>> >>>>> >>>>> >>>>> Michał. >>>>> >>>>> >>>>> >>>>> *From: *"elixir-l...@googlegroups.com" <elixir-l...@googlegroups.com> >>>>> on behalf of Bruce Tate <br...@grox.io> >>>>> *Reply to: *"elixir-l...@googlegroups.com" < >>>>> elixir-l...@googlegroups.com> >>>>> *Date: *Monday, 3 February 2020 at 11:47 >>>>> *To: *"elixir-l...@googlegroups.com" <elixir-l...@googlegroups.com> >>>>> *Subject: *Re: [elixir-core:9353] [Proposal] Add Function.const/2 >>>>> >>>>> >>>>> >>>>> My counterpoint is this. Any time you can name a concept that makes it >>>>> easier to see what's going on, it's important. >>>>> >>>>> >>>>> >>>>> Examples: >>>>> >>>>> * Create back padding of four blank table cells >>>>> >>>>> * use with Stream.repeatedly and take, for example, to initialize a >>>>> data structure for OTP. >>>>> >>>>> >>>>> >>>>> I do these two things with pretty good frequency because I build >>>>> responsive layouts often needing tabular structure, but without HTML >>>>> tables. >>>>> >>>>> >>>>> >>>>> Say you are laying out tables that are responsive but without HTML >>>>> tables. You >>>>> >>>>> d want to add padding to the end of uneven rows. To create the padding >>>>> you'd do >>>>> >>>>> >>>>> >>>>> Stream.repeatedly( fn -> :padding end) |> Enum.take(4) >>>>> >>>>> >>>>> >>>>> where :padding is the constant padding you want. This pattern comes up >>>>> with some regularity in my user interfaces. It doesn't hurt anything, and >>>>> it would be a great addition to the function module. >>>>> >>>>> >>>>> >>>>> I like this proposal. This is exactly the kind of function you'd >>>>> expect to see in the module. >>>>> >>>>> >>>>> >>>>> +1 from me. >>>>> >>>>> >>>>> >>>>> -bt >>>>> >>>>> >>>>> >>>>> On Sun, Feb 2, 2020 at 2:42 PM Jesse Claven <jesse...@gmail.com> >>>>> wrote: >>>>> >>>>> That all makes sense! I would say that in Elm it's used somewhat >>>>> frequently. I don't have access to the previous code that I worked on >>>>> (changed jobs), so unfortunately I'm unable to grep for `always` to find >>>>> some good examples. >>>>> >>>>> >>>>> >>>>> In the codebase at my new job, there's a couple of places where `fn _ >>>>> -> something` is (my original example in this thread). It's basically for >>>>> anywhere you'd want to ignore some value, and always return something >>>>> else. >>>>> I tried searching through GitHub for that code sample but the search >>>>> functionality was a little subpar. >>>>> >>>>> >>>>> >>>>> I understand about keeping the stdlib small, but for a relatively >>>>> small function, and one that's considered "table stakes" in most FP >>>>> languages, perhaps it would be a good fit? >>>>> >>>>> >>>>> On Thursday, 30 January 2020 11:20:58 UTC, Wiebe-Marten Wijnja wrote: >>>>> >>>>> The reason `Function.identity/1` was added after it was requested many >>>>> times previously, was that at some point everyone agreed that it would >>>>> improve Elixir's documentation, because it is easier to search for than >>>>> `&(&1)`. >>>>> >>>>> The `const` pattern is much less wide-spread. In e.g. Haskell it sees >>>>> some use in places where it is the single (or at least by far the >>>>> simplest) >>>>> way to make things typecheck in a pure functional environment. >>>>> >>>>> In Elixir, I suspect that it would be used much less commonly. The >>>>> fact that our functions contain statements that are executed from top to >>>>> bottom and rebindable variable names means that we are even less likely to >>>>> use it anywhere. >>>>> >>>>> As such, I don't think `const` is a function that is important enough >>>>> to include in the standard library. >>>>> >>>>> >>>>> >>>>> Of course, I'm very much open to evidence of the contrary ^_^. Do you >>>>> have any example code of where you'd see `const` being useful? >>>>> >>>>> >>>>> >>>>> ~Marten/Qqwy >>>>> >>>>> On 30-01-2020 10:24, Jesse Claven wrote: >>>>> >>>>> Hey Amos, >>>>> >>>>> >>>>> >>>>> Ah that's right. Every now and then I'm reminded that Elixir doesn't >>>>> support currying when I try to do something haha Your suggestion makes >>>>> sense. >>>>> >>>>> >>>>> >>>>> Would there be any downsides to having it, even if it isn't the most >>>>> incredible function? Again to call on the `Function.identity/1`, and it's >>>>> discussion, it's useful when it's useful for concise and semantic code. >>>>> >>>>> >>>>> On Wednesday, 29 January 2020 22:43:51 UTC, Amos King - Binary Noggin >>>>> wrote: >>>>> >>>>> Jesse, >>>>> >>>>> >>>>> >>>>> I see where you are going, but Elixir doesn't have currying. For >>>>> instance, the last example you gave will return an error. >>>>> >>>>> >>>>> >>>>> You could make it work by changing it a bit. >>>>> >>>>> >>>>> >>>>> `@spec const(a) :: fn(any() -> a) when a: var` >>>>> >>>>> >>>>> >>>>> So, const would return an fn instead of taking two arguments. I don't >>>>> know how useful that would be in the long run. I know it is common in >>>>> function programming, but I don't see it being extremely helpful in >>>>> Elixir. >>>>> >>>>> >>>>> >>>>> I'm ready to be convinced. >>>>> >>>>> >>>>> >>>>> Cheers, >>>>> >>>>> >>>>> >>>>> Amos King >>>>> >>>>> CEO >>>>> >>>>> Binary Noggin >>>>> >>>>> http://binarynoggin.com #business >>>>> >>>>> https://elixiroutlaws.com #elixir podcast >>>>> >>>>> http://thisagilelife.com #podcast >>>>> >>>>> ======================================================= >>>>> >>>>> I welcome VSRE emails. Learn more at http://vsre.info/ >>>>> >>>>> ======================================================= >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> On Wed, Jan 29, 2020 at 4:01 PM Jesse Claven <jesse...@gmail.com> >>>>> wrote: >>>>> >>>>> Hey everyone! >>>>> >>>>> I propose adding `Function.const/2` as a function which for argument >>>>> `x`, would always return `x`. >>>>> >>>>> ``` >>>>> @spec const(any(), any()) :: any() >>>>> def const(_original_value, new_value), do: new_value >>>>> ``` >>>>> >>>>> This is somewhat similar to the new `Function.identity/1` in that it >>>>> may seem like we've easily lived without it, but it does afford some more >>>>> concise/semantic ways to represent a common pattern. >>>>> >>>>> ``` >>>>> fn _ -> something_else() end >>>>> ``` >>>>> >>>>> This would become: >>>>> >>>>> ``` >>>>> const(something_else()) >>>>> ``` >>>>> >>>>> ``` >>>>> Enum.map([0,1,2,3], &Function.const/2) >>>>> ``` >>>>> >>>>> I'm new to Elixir, so I'm not sure of the weight that the name `const` >>>>> would carry, so there could be a more acceptable name. >>>>> >>>>> If accepted, I'd be happy to create a PR! >>>>> >>>>> Equivalents in other languages: >>>>> >>>>> - Haskell: >>>>> https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Function.html#v:const >>>>> - PureScript: >>>>> https://pursuit.purescript.org/packages/purescript-const/4.1.0/docs/Data.Const >>>>> - Elm: >>>>> https://package.elm-lang.org/packages/elm/core/latest/Basics#always >>>>> - Scala: >>>>> https://www.scala-lang.org/api/current/scala/Function$.html#const[T,U](x:T)(y:U):T >>>>> >>>>> - Idris: >>>>> https://www.idris-lang.org/docs/current/prelude_doc/docs/Prelude.Basics.html#Prelude.Basics.const >>>>> >>>>> >>>>> >>>>> Thanks for your time. >>>>> >>>>> >>>>> >>>>> -- >>>>> 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-l...@googlegroups.com. >>>>> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/elixir-lang-core/576949a3-93e2-4117-b1f1-ab4621f10e88%40googlegroups.com >>>>> <https://groups.google.com/d/msgid/elixir-lang-core/576949a3-93e2-4117-b1f1-ab4621f10e88%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-l...@googlegroups.com. >>>>> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/elixir-lang-core/f8b6009d-e21a-434a-96e0-e2c6ae3c1a0e%40googlegroups.com >>>>> <https://groups.google.com/d/msgid/elixir-lang-core/f8b6009d-e21a-434a-96e0-e2c6ae3c1a0e%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-l...@googlegroups.com. >>>>> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/elixir-lang-core/294d4f77-6b91-4316-a152-0c209fad12db%40googlegroups.com >>>>> <https://groups.google.com/d/msgid/elixir-lang-core/294d4f77-6b91-4316-a152-0c209fad12db%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>> . >>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> >>>>> >>>>> >>>>> Regards, >>>>> >>>>> Bruce Tate >>>>> >>>>> CEO >>>>> >>>>> >>>>> >>>>> [image: Image removed by sender.] >>>>> >>>>> >>>>> >>>>> Groxio, LLC. >>>>> >>>>> 512.799.9366 >>>>> >>>>> br...@grox.io >>>>> >>>>> grox.io >>>>> >>>>> -- >>>>> 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-l...@googlegroups.com. >>>>> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/elixir-lang-core/CAFXvW-6%3DfheYjjyQ7xiWYkP0B0t%2BfoGae9OGtkDDSvSpD4s_Sg%40mail.gmail.com >>>>> <https://groups.google.com/d/msgid/elixir-lang-core/CAFXvW-6%3DfheYjjyQ7xiWYkP0B0t%2BfoGae9OGtkDDSvSpD4s_Sg%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-l...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/elixir-lang-core/1a49eabe-6509-41c7-b425-21e207737472%40googlegroups.com >>> <https://groups.google.com/d/msgid/elixir-lang-core/1a49eabe-6509-41c7-b425-21e207737472%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-l...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/elixir-lang-core/05581EC8-0AF0-4301-8B45-4F0B78544B2D%40binarynoggin.com >>> <https://groups.google.com/d/msgid/elixir-lang-core/05581EC8-0AF0-4301-8B45-4F0B78544B2D%40binarynoggin.com?utm_medium=email&utm_source=footer> >>> . >>> >> >> >> -- >> >> Regards, >> Bruce Tate >> CEO >> >> >> <https://bowtie.mailbutler.io/tracking/hit/f8218219-d2a8-4de4-9fef-1cdde6e723f6/c7c97460-016e-45fb-a4ab-0a70318c7b97> >> >> Groxio, LLC. >> 512.799.9366 >> br...@grox.io >> grox.io >> > -- > 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/89aa185d-368d-4c95-ac41-d5e91f343b7b%40googlegroups.com > <https://groups.google.com/d/msgid/elixir-lang-core/89aa185d-368d-4c95-ac41-d5e91f343b7b%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- Austin Ziegler • halosta...@gmail.com • aus...@halostatue.ca http://www.halostatue.ca/ • http://twitter.com/halostatue -- 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/CAJ4ekQuQKUdJfBPemtqVvY%2BHHP7HHsvwx6bpGYBTu1WuM6zxbw%40mail.gmail.com.