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!

kccarter

kccarter

We’re calling into a third-party library, [Joken](https://hexdocs.pm/joken/Joken.html#t:error_reason/0), that returns the keyword list.

Our use case is decoding JWT tokens. If the token fails to validate, then there are certain conditions we can handle. (Example: the token has expired and we can refresh it.) Depending on the token we’re dealing with, we might handle things a bit differently, so we don’t have a single “decode token and handle all failures” codepath, yet.

sodapopcan

sodapopcan

To expand on the implementation of @dimitarvp’s answer, in with cond may read a little tighter:

defp act_on_error(reason) do
  cond do
    {:code, :timeout} in reason ->
      # ...

    {:code, :auth_failed} in reason ->
      # ...

    # ...
  end
end

Where Next?

Popular in Questions Top

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
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
Kagamiiiii
Student & New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
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
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

We're in Beta

About us Mission Statement