rm-rf-etc
Nicer way to pipe?
This is basically the same question I’ve asked before, I’m just wondering if anything has changed since I last asked, or if there’s any other ways to do this thing that I am doing.
I know there’s been proposals for alternate ways to pipe some input into an argument slot other than the first position, and I understand why those got shot down, so I’m not really asking about that.
Here’s an example of a function I wrote recently, and shows a style I’ve been doing kind of frequently.
def get_meter(num, total) do
Decimal.div(num, total)
|> Decimal.mult(10)
|> Decimal.round(0)
|> Decimal.to_integer()
|> (fn level ->
Enum.map(0..10, fn ^level -> "|"; _ -> "-" end)
|> Enum.join()
end).()
end
And this is another way to do the same thing, which I kind of like because we don’t have to add the extra parentheses, but we do have to add an extra level of indentation, which I find annoying.
def get_meter(num, total) do
Decimal.div(num, total)
|> Decimal.mult(10)
|> Decimal.round(0)
|> Decimal.to_integer()
|> case do
level ->
Enum.map(0..10, fn ^level -> "|"; _ -> "-" end)
|> Enum.join()
end
end
Using case is really nice when we truly have different conditions to handle in different ways, and I love that we can then pipe the result from the case statement/operator/function/macro/whatever-the-correct-term-is into whatever else comes after, but in the example shown, I don’t like it much.
The best alternative I can find to make this a little cleaner would be this:
def do_func(arg, func), do: func.(arg)
def get_meter(num, total) do
Decimal.div(num, total)
|> Decimal.mult(10)
|> Decimal.round(0)
|> Decimal.to_integer()
|> do_func(fn level ->
Enum.map(0..10, fn ^level -> "|"; _ -> "-" end)
|> Enum.join()
end)
end
Would be nice if Elixir had a built-in Kernel.do_func/2.
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #performance
- #security










First 6 of 6 Posts!
rm-rf-etc
Oh hey! This is not bad! Just realized I could make this small change.
RudManusachi
Another approach could be to use capture operator
&to create anonymous function. Plus after it we could takeEnum.join/1out to the “main pipeline”However, I think overall this pattern of wrapping code into anonymous function just to fit into pipeline is considered as bad a bad practice and it’s more preferred to break it into separate functions or intermediate values
(see GitHub - lexmag/elixir-style-guide: An opinionated Elixir style guide · GitHub
RudManusachi
There ya go! =)
rm-rf-etc
Sorry to have cut in front of you @RudManusachi.
I hear what you’re saying, but this seems it’s pretty small to break out into a separate function. Mind showing me what you think would be the best practice for this?
benwilson512
Exactly. It is not obvious what the intent of
(&Enum.map(0..10, fn ^&1 -> "|"; _ -> "-" end)).()is at all. However if you name it, then it’s a lot clearer.rm-rf-etc
'Aight, good feedback. You all were right, I moved some things around and the code got better. Thanks everyone.