Hoe gebruik je het trefwoord “met” in Elixir en waar is het voor?

In elixer 1.2 hebben ze het trefwoord “met” opgenomen, maar het is mij niet helemaal duidelijk waarvoor het dient.

Hoe en in welke situatie zou ik het gebruiken?


Antwoord 1, autoriteit 100%

In versies van Elixir ouder dan 1.2, wanneer je functies in een pijplijn gebruikt, zou je ofwel een monad-bibliotheek moeten gebruiken of nest-case-statements (die zouden kunnen worden aangepast met behulp van privé-functies, maar toch uitgebreid zouden worden). with/1biedt een andere manier om dit probleem op te lossen.

Hier is een voorbeeld van het oorspronkelijke voorstel:

case File.read(path) do
  {:ok, binary} ->
    case :beam_lib.chunks(binary, :abstract_code) do
      {:ok, data} ->
        {:ok, wrap(data)}
      error ->
        error
    end
  error ->
    error
end

Hier is hetzelfde aangepast om functies te gebruiken:

path
|> File.read()
|> read_chunks()
|> wrap()
defp read_chunks({:ok, binary}) do
  {:ok, :beam_lib.chunks(binary, :abstract_code)}
end
defp read_chunks(error), do: error
defp wrap({:ok, data}) do
  {:ok, wrap(data)}
end
defp wrap(error), do: error

En dezelfde code met with:

with {:ok, binary} <- File.read(path),
     {:ok, data} <- :beam_lib.chunks(binary, :abstract_code),
     do: {:ok, wrap(data)}

Dit werkt omdat withalleen blijft ketenen als de waarde overeenkomt met het patroon aan de linkerkant. Zo niet, dan wordt de keten afgebroken en wordt het eerste niet-overeenkomende resultaat geretourneerd. Als het bestand bijvoorbeeld niet bestaat, zal File.read(path){:error, :enoent}retourneren – dit komt niet overeen met {:ok, binary}dus de with/1aanroep retourneert {:error, :enoent}.

Het is vermeldenswaard dat with kan worden gebruikt met elk patroon, niet alleen {:ok, foo}en {:error, reason}(hoewel het een zeer veelvoorkomend gebruik).


Antwoord 2, autoriteit 22%

Je kunt ook “kale uitdrukkingen” koppelen, zoals de doc zegt:

with {:ok, binary} <- File.read(path),
     header = parse_header(binary),
     {:ok, data} <- :beam_lib.chunks(header, :abstract_code),
     do: {:ok, wrap(data)}

De variabele headeris alleen beschikbaar binnen de with-instructie. Meer info op https://gist.github.com/josevalim/8130b19eb62706e1ab37


Antwoord 3, autoriteit 5%

Eén ding om te vermelden is dat je whenguard in withstatement kunt gebruiken.
Bijvoorbeeld

defmodule Test do
  def test(res) do
    with {:ok, decode_res} when is_map(decode_res) <- res
    do
      IO.inspect "ok"
    else
      decode_res when is_map(decode_res) -> IO.inspect decode_res
      _ ->
        IO.inspect "error"
    end
  end
end
Test.test({:ok , nil})
Test.test({:ok , 12})
Test.test({:ok , %{}})

Other episodes