kccarter

kccarter

What is the preferred way to pattern match a Keyword list inside a Case?

Is there an idiomatic way in Elixir to write a case guard to pattern match on the value of a key inside a Keyword List?

The keyword list has an arbitrary number of keywords, so matching agains the entire list is not an option.

The best we can come up with is a nested case statement to match against Keyword.get, is there a cleaner way?

# Contrived example for discussion purposes.
def run_something(args) do 
  
  # calculate_something returns:
  #   {:ok, response}
  #   {error, [message: string, code: atom, ...] }

  case calculate_something(args) do
    {:ok, response} -> 
      response

    # How do you perform such a pattern match? 
    {:error, reason} when Keyword.get(reason, code:) == :timeout -> 
      # Maybe try again? 

    {:error, reason} when Keyword.get(reason, code:) == :auth_failed -> 
      # Maybe try to re-authenticate? 
    
    {:error, reason } -> 
      # Unknown reason, abort.
  end
end

Marked As Solved

dimitarvp

dimitarvp

Keyword list keys can be duplicated, and they can be at an arbitrary position as well, so the answer to your direct question is “no”. You can pattern match e.g. [{:desired_key, _value} | _rest] but that will only work if :desired_key is the key of the first element in a keyword list and in no other conditions.

I don’t view your code as boilerplate-y or clunky but if there is a chance that those error clauses can explode you can indeed just make a helper function i.e.

case stuff do
   {:ok, value} -> value
   {:error, anything} -> act_on_error(anything)
end

…and then use the Keyword module functions inside the helper function to manipulate the embedded error value further.

Also Liked

sodapopcan

sodapopcan

Because the order of HTTP headers can matter if some have the same name. This encompasses two important qualities of keyword lists! You can probably think of other examples of where order matters. As for duplicate keys, these are used in Elixir’s import: import String, only: [split: 1, split: 2] as well as Ecto: from q in query, where: q.a == 1, where q.b = 1. Maps have efficient look up but they don’t maintain their order and of course cannot have duplicate keys.

EDIT: Fix wording and examples.

kip

kip

ex_cldr Core Team

Note too that you can’t invoke arbitrary functions in a guard. Guards need a constant time execution guarantee and therefore only a small set of functions are permitted.

If you really need structured results, consider using a map rather than a keyword list. Map keys can be used in guard clauses.

kccarter

kccarter

Now that is a syntax we would not have considered as new Elixir developers. I guess this works because a keyword list is just a list of 2-item tuples. TIL, thanks!

Where Next?

Popular in Questions Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
JulienCorb
I am trying to implement my new.html.eex file to create new posts on my website. new.html.eex: <h1>Create Post</h1> <%= ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement