Conditional pipe ?>

939 views
Skip to first unread message

Michael Kohl

unread,
Jan 9, 2015, 1:32:21 AM1/9/15
to elixir-l...@googlegroups.com
Hi!

Before I put any actual effort into this, would there be interest in a pipe macro that works like |> but ignores nil values? Think Groovy's ?. [1] or Clojure's some-> macro [2].

Here's a quick implementation with the proposed operator (?>):

defmacro left ?> right do 
   [{h, _}|t] = Macro.unpipe({:|>, [], [left, right]}) 
   case h do 
     nil -> nil 
     _ -> :lists.foldl fn {x, pos}, acc -> Macro.pipe(acc, x, pos) end, h, t 
   end 
end

Example:

iex(21)> inc = &(&1+1) 
#Function<6.90072148/1 in :erl_eval.expr/5> 
iex(22)> nil |> inc.() 
** (ArithmeticError) bad argument in arithmetic expression :erlang.+(nil, 1) 
iex(22)> nil ?> inc.() 
nil

Cheers,
Michael

References:


José Valim

unread,
Jan 9, 2015, 3:25:38 AM1/9/15
to elixir-l...@googlegroups.com
Hello Michael, we had previous discussions about this in the mailing list that are worth revisiting.

I don't think a ?> (or the previously proposed &&>) operator makes sense because that nil is not the only pattern you would like to match on. For example, you may also want to pipe only if the response matches {:ok, _} and so on. Throughout time, I have thought about different ways of solving this and others too.

1. The elixir-pipes project allow you to be explicit on what you want to match and return, for example:

# pipe_matching(match, return, pipes)
pipe_matching {:ok, x}, x, foo |> bar |> baz
pipe_matching x when x != nil, x, foo |> bar |> baz

2. Allow case to match on multiple patterns:

case {:ok, x} <- foo,
     {:ok, y} <- bar(x),
     baz(y)

3. And today, for your particular problem, you can at least write:

(x =  foo()) && (y = bar(x)) && baz(z)





José Valim
Skype: jv.ptec
Founder and Lead Developer

--
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-co...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Michael Kohl

unread,
Jan 9, 2015, 3:58:24 AM1/9/15
to elixir-l...@googlegroups.com, jose....@plataformatec.com.br
Thanks Jose!


I figured there must have been similar discussions, but a quick search hadn't brought up anything useful. I guess my search terms were off.



On Friday, January 9, 2015 at 3:25:38 PM UTC+7, José Valim wrote:
1. The elixir-pipes project allow you to be explicit on what you want to match and return, for example:

This (https://github.com/batate/elixir-pipes) does indeed look pretty neat.
 
2. Allow case to match on multiple patterns:

case {:ok, x} <- foo,
     {:ok, y} <- bar(x),
     baz(y)

Promising. Maybe add some syntactic sugar similar to Haskell's do-notation (there was something similar in the now outdated elixir-monad project). Something like this maybe, although that's very similar to the pipes project mentioned above.

result = matching {:ok, x} do
  foo
  bar(x)
  baz(x)
end
 
3. And today, for your particular problem, you can at least write:

I know I can, it's just the type of code I'm trying to avoid. 

I think my main problem is approaching Erlang like Haskell or other languages that have an Option/Maybe type, so I'm probably trying to translate an idiom that doesn't fit with the paradigm. 

Thanks for taking the time to respond,
Michael
Reply all
Reply to author
Forward
0 new messages