I’m voting for adding the concept. Bruce sold me with his arguments. Amos King CEO Binary Noggin
> On Feb 5, 2020, at 15:16, Jesse Claven <[email protected]> wrote: > > > Thanks everyone for the good discussion! Especially Bruce who was better able > to explain what I was trying to explain. I don't have much to add aside from > what he, and others have said. > > > 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. > > As someone who has now been using Elixir professionally for just over a > month, I agree. ftr I do really like Elixir. ;) > >> On Tuesday, 4 February 2020 16:09:51 UTC, Austin Ziegler wrote: >>> On Tue, Feb 4, 2020 at 10:04 AM Ben Wilson <[email protected]> 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 <[email protected]> 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 <[email protected]> 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: "[email protected]" <[email protected]> on >>>>>>>> behalf of Bruce Tate <[email protected]> >>>>>>>> Reply to: "[email protected]" <[email protected]> >>>>>>>> Date: Monday, 3 February 2020 at 11:47 >>>>>>>> To: "[email protected]" <[email protected]> >>>>>>>> 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 <[email protected]> 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 <[email protected]> >>>>>>>> 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 [email protected]. >>>>>>>> To view this discussion on the web visit >>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/576949a3-93e2-4117-b1f1-ab4621f10e88%40googlegroups.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 [email protected]. >>>>>>>> To view this discussion on the web visit >>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/f8b6009d-e21a-434a-96e0-e2c6ae3c1a0e%40googlegroups.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 [email protected]. >>>>>>>> To view this discussion on the web visit >>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/294d4f77-6b91-4316-a152-0c209fad12db%40googlegroups.com. >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> Regards, >>>>>>>> >>>>>>>> Bruce Tate >>>>>>>> >>>>>>>> CEO >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> Groxio, LLC. >>>>>>>> >>>>>>>> 512.799.9366 >>>>>>>> >>>>>>>> [email protected] >>>>>>>> >>>>>>>> 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 [email protected]. >>>>>>>> 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. >>>>>>>> >>>>>>>> >>>>>> >>>>>> -- >>>>>> 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 [email protected]. >>>>>> To view this discussion on the web visit >>>>>> https://groups.google.com/d/msgid/elixir-lang-core/1a49eabe-6509-41c7-b425-21e207737472%40googlegroups.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 [email protected]. >>>>> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/elixir-lang-core/05581EC8-0AF0-4301-8B45-4F0B78544B2D%40binarynoggin.com. >>>> >>>> >>>> -- >>>> >>>> Regards, >>>> Bruce Tate >>>> CEO >>>> >>>> >>>> >>>> Groxio, LLC. >>>> 512.799.9366 >>>> [email protected] >>>> 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 [email protected]. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/elixir-lang-core/89aa185d-368d-4c95-ac41-d5e91f343b7b%40googlegroups.com. >> >> >> -- >> Austin Ziegler • [email protected] • [email protected] >> 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 [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/c7496796-b29c-4039-b95d-c76bb7d9c6a1%40googlegroups.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 [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/51B16417-DA9D-4C36-BDB6-CB522285229C%40binarynoggin.com.
