Ricerca…


Funzioni anonime

In Elixir, una pratica comune è usare le funzioni anonime. La creazione di una funzione anonima è semplice:

iex(1)> my_func = fn x -> x * 2 end
#Function<6.52032458/1 in :erl_eval.expr/5>

La sintassi generale è:

fn args -> output end

Per migliorare la leggibilità, puoi mettere le parentesi attorno agli argomenti:

iex(2)> my_func = fn (x, y) -> x*y end
#Function<12.52032458/2 in :erl_eval.expr/5>

Per richiamare una funzione anonima, chiamala con il nome assegnato e aggiungi . tra il nome e gli argomenti.

iex(3)>my_func.(7, 5)
35

È possibile dichiarare funzioni anonime senza argomenti:

iex(4)> my_func2 = fn -> IO.puts "hello there" end
iex(5)> my_func2.()
hello there
:ok

Utilizzando l'operatore di cattura

Per rendere più concise le funzioni anonime è possibile utilizzare l' operatore di cattura & . Ad esempio, invece di:

iex(5)> my_func = fn (x) -> x*x*x end

Tu puoi scrivere:

iex(6)> my_func = &(&1*&1*&1)

Con più parametri, utilizza il numero corrispondente a ciascun argomento, contando da 1 :

iex(7)> my_func = fn (x, y) -> x + y end

iex(8)> my_func = &(&1 + &2)   # &1 stands for x and &2 stands for y

iex(9)> my_func.(4, 5)
9

Corpi multipli

Una funzione anonima può anche avere più corpi (come risultato della corrispondenza del modello ):

my_func = fn
  param1 -> do_this
  param2 -> do_that
end

Quando si chiama una funzione con più corpi, l'elisir tenta di far corrispondere i parametri forniti con il corpo della funzione appropriata.

Elenchi di parole chiave come parametri di funzione

Utilizza gli elenchi di parole chiave per i parametri di stile "opzioni" che contengono più coppie chiave-valore:

def myfunc(arg1, opts \\ []) do
  # Function body
end

Possiamo chiamare la funzione sopra in questo modo:

iex> myfunc "hello", pizza: true, soda: false

che è equivalente a:

iex> myfunc("hello", [pizza: true, soda: false])

I valori degli argomenti sono disponibili rispettivamente come opts.pizza e opts.soda .
In alternativa, potresti usare gli atomi: opts[:pizza] e opts[:soda] .

Funzioni nominate e funzioni private

Funzioni nominate

defmodule Math do
    # one way
    def add(a, b) do
        a + b
    end

    # another way
    def subtract(a, b), do: a - b
end

iex> Math.add(2, 3)
5
:ok
iex> Math.subtract(5, 2)
3
:ok

Funzioni private

defmodule Math do
    def sum(a, b) do
        add(a, b)
    end

    # Private Function
    defp add(a, b) do
        a + b
    end
end

iex> Math.add(2, 3)
** (UndefinedFunctionError) undefined function Math.add/2
Math.add(3, 4)
iex> Math.sum(2, 3)
5

Pattern Matching

L'elisir corrisponde una chiamata di funzione al suo corpo in base al valore dei suoi argomenti.

defmodule Math do
    def factorial(0): do: 1
    def factorial(n): do: n * factorial(n - 1)
end

Qui, fattoriale di numeri positivi corrisponde alla seconda clausola, mentre factorial(0) corrisponde alla prima. (ignorando i numeri negativi per motivi di semplicità). L'elisir cerca di far corrispondere le funzioni dall'alto verso il basso. Se la seconda funzione è scritta sopra la prima, avremo un risultato inaspettato mentre si procede verso una ricorsione senza fine. Perché factorial(0) corrisponde a factorial(n)

Clausole di guardia

Le clausole di guardia ci consentono di controllare gli argomenti prima di eseguire la funzione. Le clausole di guardia sono solitamente preferite a if e cond causa della loro leggibilità e per rendere più semplice una determinata tecnica di ottimizzazione per il compilatore. La prima definizione di funzione in cui tutte le protezioni corrispondono viene eseguita.

Ecco un esempio di implementazione della funzione fattoriale usando le protezioni e la corrispondenza del modello.

defmodule Math do
    def factorial(0), do: 1
    def factorial(n) when n > 0: do: n * factorial(n - 1)
end

Il primo schema corrisponde se (e solo se) l'argomento è 0 . Se l'argomento non è 0 , la corrispondenza del modello fallisce e viene controllata la funzione successiva.

Quella seconda definizione di funzione ha una clausola di guardia: when n > 0 . Ciò significa che questa funzione corrisponde solo se l'argomento n è maggiore di 0 . Dopo tutto, la funzione fattoriale matematica non è definita per gli interi negativi.

Se nessuna delle definizioni di funzione (incluse la corrispondenza del modello e le clausole di protezione) corrispondono, verrà generato un FunctionClauseError . Questo accade per questa funzione quando passiamo un numero negativo come argomento, poiché non è definito per i numeri negativi.

Notare che questo FunctionClauseError stesso non è un errore. Restituire -1 o 0 o qualche altro "valore di errore" come è comune in alcune altre lingue nasconderebbe il fatto che hai chiamato una funzione indefinita, nascondendo la fonte dell'errore, creando probabilmente un enorme bug doloroso per un futuro sviluppatore.

Parametri predefiniti

È possibile passare i parametri predefiniti a qualsiasi funzione denominata utilizzando la sintassi: param \\ value :

defmodule Example do
    def func(p1, p2 \\ 2) do
        IO.inspect [p1, p2]
    end
end

Example.func("a")    # => ["a", 2]
Example.func("b", 4) # => ["b", 4]

Cattura le funzioni

Usa & per acquisire funzioni da altri moduli. È possibile utilizzare le funzioni acquisite direttamente come parametri di funzione o all'interno di funzioni anonime.

Enum.map(list, fn(x) -> String.capitalize(x) end)

Può essere reso più conciso usando & :

Enum.map(list, &String.capitalize(&1))

Catturare le funzioni senza passare alcun argomento richiede di specificare esplicitamente la propria appartenenza, ad esempio &String.capitalize/1 :

defmodule Bob do
  def say(message, f \\ &String.capitalize/1) do
    f.(message)
  end
end


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow