Elixir에서 익명 함수와 사귀는 방법

16616 단어 Elixir
Elixir에서 익명 함수를 사용하는 장면은 많이 있습니다.

각각의 쓰는 방법의 이용예, 메리트, 단점을 들고 갑니다.

또한 함수의 익명 함수화 및 파이프 라인 연산자와의 복합에 대해서도 다룹니다.

환경


$ elixir --version
Erlang/OTP 23 [erts-11.0.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Elixir 1.10.3 (compiled with Erlang/OTP 23)

익명 함수 선언 구문



1. fn ... end 표기법



기본적인 것으로 든다면, fn .. end 기법이겠지요.

익명 함수를 배우는 데 먼저 쓰는 것이라고 생각합니다.

이용 예 1 (간단한 인수 선언)


double = fn num -> num * 2 end

# 単純な呼び出し
double.(3)
# => 6

# Enum.map/2と合わせる
Enum.map([1, 2, 4, 8], double)
# => [2, 4, 8, 16]

이용 예 2 (인수로 패턴 매칭을 실시한다)


# 要素数が2の配列を受け取り、2つの位置を入れ替える
swap = fn [a, b] -> [b, a] end

swap.([1, 2])
# => [2, 1]

# caseのように、パターンマッチングによって処理を変える
reverse =
  fn
    [a, b]    -> [b, a]
    [a, b, c] -> [c, b, a]
  end

reverse.([1, 2])
# => [2, 1]

reverse.([1, 2, 3])
# => [3, 2, 1]

패턴 매칭에 대한 자세한 내용은 Elixir School을 참조하십시오.
def ... end 에서의 함수 선언을 할 정도는 아니지만, 세세한 것을 하고 싶은 경우에 매우 유효합니다.

이용예 3(데이터형의 패턴 매칭을 실시한다)



또, MapTuple 등의 데이터형 배열을 취급하는 경우에는 효력을 발휘합니다.

&(...) 기법의 경우
# Map
user1 = %{name: "alice", age: 15}
user2 = %{name: "bob"  , age: 19}
user3 = %{name: "carol", age: 23}

users = [user1, user2, user3]

user_names = Enum.map(users, fn %{name: name} -> name end)
# => ["alice", "bob", "carol"]

# Tuple
result1 = {:ok, 1}
result2 = {:ok, 2}
result3 = {:ok, 3}

results = [result1, result2, result3]

Enum.map(results, fn {:ok, num} -> num end)
# => [1, 2, 3]

특정 키만 이용하고 싶은 장면에서 리더블에 쓸 수 있습니다.

장점


  • 후술한다 &(...) 기법보다 인수명이 명시적이 된다
  • 복수 행에 걸친 처리를 쓰기 쉽다
  • 인수로 패턴 매칭을 할 수있다

  • 단점


  • 단순히 인수를 늘어놓는 것만으로는, &(...) 기법 쪽이 간결

  • 2. &(...) 기법(캡처 연산자)



    간단한 인수를 취하는 인라인 선언이라면이 기법을 이용하는 것이 가장 좋습니다.

    인수 수치, 인수의 순서가 확실히 보기 때문에 알기 어려우므로, 많이 사용해서는 안 된다고 생각합니다. 코멘트가 필요 없을 정도로 짧은 코드라면 문제는 없습니다.

    인수를 건네준 순서대로 플레이스홀더에 바인딩 됩니다.

    이용예 1


    double = &(&1 * 2)
    
    double.(3)
    # => 6
    

    이용예 2(데이터형 배열의 단순한 이용)



    fn...end 표기법의 경우
    user1 = %{name: "alice", age: 15}
    user2 = %{name: "bob"  , age: 19}
    user3 = %{name: "carol", age: 23}
    
    users = [user1, user2, user3]
    
    user_names = Enum.map(users, &(&1.name))
    # => ["alice", "bob", "carol"]
    

    장점


  • 인수 선언이 없기 때문에 간결하게 쓸 수 있다
  • 간단한 처리라면 가독성이 높아진다

  • 단점


  • 여러 줄로 처리하지 않습니다
  • fn ... end 표기법과 달리 인수의 패턴 매칭이 불가능합니다

  • 3. 캡처 연산자로 함수 익명 함수화



    익명 함수를 인수로 사용하는 함수에는 함수를 전달하는 장면도 있습니다.

    위에서 언급 한 fn ... end&(...) 와 같이, &에 이어 함수명/알리티라고 기술하는 것으로 익명 함수화를 실시할 수 있습니다.
    또한 자리 표시자를 사용할 수 있습니다.

    이용예 1


    # 以下の全てのコードは等価
    # &(...) 記法
    Enum.map([1, 2, 3, 5], &(to_string(&1)))
    # => ["1", "2", "3", "5"]
    
    # アリティ付きで渡す
    Enum.map([1, 2, 3, 5], &to_string/1)
    
    # プレースホルダを引数にする
    Enum.map([1, 2, 3, 5], &to_string(&1))
    

    사용 예 2 (부분 적용한 익명 함수를 건네준다)


    &to_string/1 와 같이 앨리티 1을 인수에 취하는 함수에 건네주는 경우는 부분적용(컬리화)하는 것으로 호출할 수 있습니다.
    부분적 적용은 이 기사의 본질이 아니므로 설명하지 않습니다.
    # &(...) 記法
    add_two = &(2 + &1)
    
    # 部分適用
    add_two = &Kernel.+(2, &1)
    
    add_two.(3)
    # => 5
    
    Enum.map([1, 2, 4, 8], add_two)
    # => [3, 4, 6, 10]
    

    4. 파이프라인 연산자와 결합



    여기까지는 익명 함수의 선언과 이용 예를 들었습니다.
    Elixir답게 파이프라인 연산자와 조합해 봅시다.

    파이프라인 연산자로 익명 함수를 호출하려면 , 통상 함수의 호출과 같게 제일 인수를 생략하는 것으로 &Kernel.+/2 그리고 호출할 수 있습니다.
    double = &(&1 * 2)
    
    3 |> double.()
    # => 6
    
    # パイプライン演算子に直接匿名関数を渡す場合は()で括り、実引数を渡す
    3 |> (&(&1*2)).()
    
    5 |> (&(&1*&2)).(2)
    # => 10
    

    이용 예


    require Integer
    
    double = &(&1 * 2)
    triple = &(&1 * 3)
    
    number =
      1..10
      |> Enum.random
    
    number
    |> Integer.is_odd
    |> (fn
      # 奇数なら3倍
      true , num -> triple.(num)
      # 偶数なら2倍
      false, num -> double.(num)
    end).(number)
    |> to_string
    

    요약



    익명 함수를 잘 다루는 것으로 리더블이 되는 것을 실감할 수 있었다고 생각합니다.

    Elixir로 쓰면 자르지 않을 수 있습니다. 확실히 익히십시오.

    좋은 웹페이지 즐겨찾기