Elixir匿名函数 #

一、匿名函数定义 #

1.1 基本语法 #

elixir
iex(1)> fn x -> x * 2 end
#Function<...>

iex(2)> add = fn a, b -> a + b end
#Function<...>

1.2 调用匿名函数 #

使用 . 调用匿名函数:

elixir
iex(1)> add = fn a, b -> a + b end
#Function<...>

iex(2)> add.(1, 2)
3

iex(3)> double = fn x -> x * 2 end
#Function<...>

iex(4)> double.(5)
10

1.3 多行函数 #

elixir
iex(1)> greet = fn name ->
...>   message = "Hello, #{name}!"
...>   IO.puts(message)
...>   message
...> end
#Function<...>

iex(2)> greet.("Alice")
Hello, Alice!
"Hello, Alice!"

二、模式匹配 #

2.1 多子句匿名函数 #

elixir
iex(1)> handle = fn
...>   {:ok, result} -> "Success: #{result}"
...>   {:error, reason} -> "Error: #{reason}"
...> end
#Function<...>

iex(2)> handle.({:ok, "data"})
"Success: data"

iex(3)> handle.({:error, "not found"})
"Error: not found"

2.2 带守卫的匿名函数 #

elixir
iex(1)> categorize = fn
...>   x when x < 0 -> :negative
...>   0 -> :zero
...>   x when x > 0 -> :positive
...> end
#Function<...>

iex(2)> categorize.(-5)
:negative

iex(3)> categorize.(0)
:zero

iex(4)> categorize.(5)
:positive

2.3 列表处理 #

elixir
iex(1)> process = fn
...>   [] -> "Empty list"
...>   [head | tail] -> "Head: #{head}, Tail: #{inspect(tail)}"
...> end
#Function<...>

iex(2)> process.([])
"Empty list"

iex(3)> process.([1, 2, 3])
"Head: 1, Tail: [2, 3]"

三、闭包 #

3.1 捕获外部变量 #

匿名函数可以捕获定义时的外部变量:

elixir
iex(1)> prefix = "Hello, "
"Hello, "

iex(2)> greet = fn name -> prefix <> name end
#Function<...>

iex(3)> greet.("Alice")
"Hello, Alice"

3.2 闭包示例 #

elixir
iex(1)> counter = fn ->
...>   count = 0
...>   fn ->
...>     count = count + 1
...>   end
...> end
#Function<...>

iex(2)> c = counter.()
#Function<...>

iex(3)> c.()
1

iex(4)> c.()
2

3.3 工厂函数 #

elixir
defmodule Multiplier do
  def create(factor) do
    fn x -> x * factor end
  end
end

double = Multiplier.create(2)
triple = Multiplier.create(3)

double.(5)
triple.(5)

四、捕获操作符 #

4.1 基本用法 #

使用 & 捕获函数:

elixir
iex(1)> add = &+/2
&:erlang.+/2

iex(2)> add.(1, 2)
3

iex(3)> length_func = &length/1
&:erlang.length/1

iex(4)> length_func.([1, 2, 3])
3

4.2 捕获命名函数 #

elixir
iex(1)> upcase = &String.upcase/1
&String.upcase/1

iex(2)> upcase.("hello")
"HELLO"

iex(3)> split = &String.split/2
&String.split/2

iex(4)> split.("a,b,c", ",")
["a", "b", "c"]

4.3 简写语法 #

elixir
iex(1)> double = &(&1 * 2)
#Function<...>

iex(2)> double.(5)
10

iex(3)> add = &(&1 + &2)
#Function<...>

iex(4)> add.(1, 2)
3

iex(5)> greet = &("Hello, " <> &1)
#Function<...>

iex(6)> greet.("Alice")
"Hello, Alice"

4.4 与Enum配合 #

elixir
iex(1)> Enum.map([1, 2, 3, 4, 5], &(&1 * 2))
[2, 4, 6, 8, 10]

iex(2)> Enum.filter([1, 2, 3, 4, 5], &(&1 > 2))
[3, 4, 5]

iex(3)> Enum.reduce([1, 2, 3, 4, 5], &+/2)
15

iex(4)> Enum.map(["hello", "world"], &String.upcase/1)
["HELLO", "WORLD"]

五、函数作为参数 #

5.1 高阶函数 #

elixir
iex(1)> apply_twice = fn func, value ->
...>   func.(func.(value))
...> end
#Function<...>

iex(2)> double = fn x -> x * 2 end
#Function<...>

iex(3)> apply_twice.(double, 5)
20

5.2 自定义高阶函数 #

elixir
defmodule Collection do
  def my_map(list, func) do
    case list do
      [] -> []
      [head | tail] -> [func.(head) | my_map(tail, func)]
    end
  end

  def my_filter(list, pred) do
    case list do
      [] -> []
      [head | tail] ->
        if pred.(head) do
          [head | my_filter(tail, pred)]
        else
          my_filter(tail, pred)
        end
    end
  end

  def my_reduce(list, acc, func) do
    case list do
      [] -> acc
      [head | tail] -> my_reduce(tail, func.(head, acc), func)
    end
  end
end

六、函数组合 #

6.1 简单组合 #

elixir
iex(1)> compose = fn f, g ->
...>   fn x -> f.(g.(x)) end
...> end
#Function<...>

iex(2)> double = &(&1 * 2)
#Function<...>

iex(3)> increment = &(&1 + 1)
#Function<...>

iex(4)> double_then_increment = compose.(increment, double)
#Function<...>

iex(5)> double_then_increment.(5)
11

6.2 管道风格 #

elixir
iex(1)> pipe = fn f, g ->
...>   fn x -> g.(f.(x)) end
...> end
#Function<...>

iex(2)> process = pipe.(
...>   &String.upcase/1,
...>   &String.reverse/1
...> )
#Function<...>

iex(3)> process.("hello")
"OLLEH"

七、部分应用 #

7.1 固定参数 #

elixir
iex(1)> partial_add = fn a ->
...>   fn b -> a + b end
...> end
#Function<...>

iex(2)> add_five = partial_add.(5)
#Function<...>

iex(3)> add_five.(3)
8

7.2 使用捕获操作符 #

elixir
iex(1)> add_five = &(&1 + 5)
#Function<...>

iex(2)> add_five.(3)
8

iex(3)> starts_with_hello? = &String.starts_with?(&1, "Hello")
#Function<...>

iex(4)> starts_with_hello?.("Hello, World")
true

八、递归匿名函数 #

8.1 使用引用 #

elixir
iex(1)> factorial = fn
...>   0, _ -> 1
...>   n, self -> n * self.(n - 1, self)
...> end
#Function<...>

iex(2)> factorial.(5, factorial)
120

8.2 Y组合子 #

elixir
iex(1)> y = fn f ->
...>   (fn x -> f.(fn y -> x.(x).(y) end) end).(fn x -> f.(fn y -> x.(x).(y) end) end)
...> end
#Function<...>

iex(2)> factorial = y.(fn f ->
...>   fn
...>     0 -> 1
...>     n -> n * f.(n - 1)
...>   end
...> end)
#Function<...>

iex(3)> factorial.(5)
120

九、函数类型 #

9.1 类型规范 #

elixir
@spec add(number(), number()) :: number()
def add(a, b), do: a + b

@spec map(list(a()), (a() -> b())) :: list(b())
def map(list, func) do
  Enum.map(list, func)
end

9.2 函数类型检查 #

elixir
iex(1)> is_function(fn x -> x end)
true

iex(2)> is_function(fn x -> x end, 1)
true

iex(3)> is_function(fn x -> x end, 2)
false

十、总结 #

本章学习了:

特性 示例
定义 fn x -> x end
调用 func.(arg)
多子句 fn {:ok, x} -> x; {:error, _} -> nil end
闭包 捕获外部变量
捕获操作符 &String.upcase/1, &(&1 * 2)
高阶函数 函数作为参数或返回值

准备好学习命名函数了吗?让我们进入下一章。

最后更新:2026-03-27