Fork me on GitHub

elixir函数式编程

elixir functional program

Posted by Kaelzhang on November 18, 2015

img

如果你听说过elixir的话,那么你应该知道elixir是基于erlang的vm的,而erlang语言是一个纯函数式编程(functional programming,FP)的语言,那么elixir是不是纯FP语言呢?答案是肯定的,elixir具备erlang FP的绝大多数特性,在少数细节上面有差异。下面将从四个FP基本特性来讲解:

  1. 函数是一等类型(First-Class Functions)

  2. 高阶函数(Higher-Order Functions)

  3. 闭包(Closures)

  4. 不变性(Immutable State)

函数是一等类型(First-Class Functions)

函数独立存在,不依附于任何对象或者命名空间,函数就是数据,就如同数据结构、数字以及字符串一样。匿名函数是该特性的最好体现。

elixir示例:

iex(1)> add = &(&1 + &2)
&:erlang.+/2
iex(2)> sub = &(&1 - &2)
&:erlang.-/2
iex(3)> calc = &(&3.(&1, &2))
#Function<18.54118792/3 in :erl_eval.expr/5>
iex(4)> IO.inspect add.(1,2)
3
3
iex(5)> IO.inspect sub.(2,4)
-2
-2
iex(6)> IO.inspect calc.(1, 2, add)
3
3
iex(7)> IO.inspect calc.(2, 4, sub)
-2
-2
iex(8)> IO.inspect calc.(2, 4, &(&1 * &2))
8
8
iex(9)>

高阶函数(Higher-Order Functions)

在上面的示例中已经对高阶函数的特点进行了展示。所谓高阶函数,是指接受函数作为参数,或者把函数作为返回值的函数。再多举个elixir的例子:

elixir示例:

iex(9)> square = fn x -> x * x end
#Function<6.54118792/1 in :erl_eval.expr/5>
iex(10)> Enum.map(1..10, square)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
iex(11)>

闭包(Closures)

闭包包含两个特性:

  1. 能够被传递
  2. 当函数被创建的时候,所有变量的值都在该函数的作用域内,这些变量的值总是能够被访问的,并且和创建时一致

elixir示例:

iex(1)> var = 5
5
iex(2)> print = fn -> IO.puts(var) end
#Function<20.54118792/0 in :erl_eval.expr/5>
iex(3)> var = 6
6
iex(4)> print.()
5
:ok
iex(5)>

不变性(Immutable State)

首先,elixir是具有不变性的。不变性的强大体现在竞争和强占上,也就是说不会出现两个流程同时去改变同一个值的情况。

elixir示例:

iex(5)> tuple={:ok, "hello"}
{:ok, "hello"}
iex(6)> put_elem(tuple,1,"world")
{:ok, "world"}
iex(7)> tuple
{:ok, "hello"}
iex(8)>

然而elixir较之erlang有些差异,那就是elixir可以对变量进行重新绑定。如果仅仅对变量进行模式匹配的话可在变量前加上^。

elixir示例:

iex(8)> num = 1
1
iex(9)> ^num = 2
** (MatchError) no match of right hand side value: 2

iex(9)> num = 2
2
iex(10)> ^num = 2
2

在举个不变性的例子,我先定义一个名为Assignment的模块:

elixir示例:

defmodule Assignment do
    def change_me(string) do
        string = 2
    end
end

下面编译该模块,并调用change_me改变传入的变量string为数值2。

elixir示例:

iex(1)> greeting = "Hello"
"Hello"
iex(2)> Assignment.change_me(greeting)
2
iex(3)> greeting
"Hello"

结果greeting未发生变化,依旧为“hello”

参考文献:


  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!