Pattern matching with sigils

Hi, having a problem refactoring using pattern matching for these lines of code

defp check_input(input, game = %State{}) do
  input = String.trim(input)
  cond do
    input =~ ~r/\A[a-z]\z/ ->
      Map.put(game, :guess, input)
    true ->
      IO.puts "please enter a lower-case letter"
      accept_move(game)
  end
end

Basically what I want to do is refactor the conditional logic, but I can’t seem to find a way to pattern match sigils using the where clause. Can anybody show me how?

As you can see here https://hexdocs.pm/elixir/guards.html =~ is not listed in the list of things you can use within a guard clause. And while you can use sigils in pattern matches executing a regex is not possible as part of a pattern match or guard clause.

1 Like

does this mean it is not possible to refactor this conditional logic into a new function?

Of course…

def only_single_lowercase(<<c::utf8>>), do: c in ?a..?z
4 Likes

so for the latter condition would be something like this

def only_single_lowercase(<<boolean>>) do
      IO.puts "please enter a lower-case letter"
      accept_move(game)
end

what would that argument be? and where is the documentation for <>? thanks

No, you use only single lowercase instead of your current match.

Based on this you should be able to build a two clause function that replaces your current function.

Documentation for the <<>>/1 can be found in the docs :wink:

so how do you write a multi clause function for this case?

def only_single_lowercase(<<c::utf-8>>), do: c in ?a..?z

and

def only_single_lowercase(input) where is_boolean(input) do
      IO.puts "please enter a lower-case letter"
      accept_move(game)
end

these are my two clauses. I apologize, this isn’t what i’m used to and i’m lost.

I’m not quite sure where you get the is_boolean/1 from. I never used that.

The first step is (as I said already) to simply replace your first condition with my function:

defp check_input(input, game = %State{}) do
  input = String.trim(input)
  cond do
    only_single_lowercase(input) ->
      Map.put(game, :guess, input)
    true ->
      IO.puts("please enter a lower-case letter"
      accept_move(game)
  end
end

The next step is to rewrite the cond into a case (and inline my function):

def check_input(input, game = %State{}) do
  input
  |> String.trim()
  |> case do
    <<c::utf8>> when c in ?a..?z ->
      Map.put(game, :guess, input)
    _ ->
      IO.puts(…)
      accept_move(game)
  end
end

And now it should be easy to extract this 2-clause case into a 2-clause function.