과거 칼럼 ZEN Style화①:재귀로 쓰인 key에 의한 로직 전환(Strategy/State 패턴을 Elixir답게 스마트하게)

13435 단어 fukuoka.exElixir
후쿠오카. 그림 x/고쿠라. 그림 x의 piacere입니다.
방문해 주셔서 감사합니다

과거 Qiita Elixir 칼럼을 "Elixir ZEN Style"로 다시 작성하면 어떻게 될지의 미니 칼럼입니다.

이번에는, @다루이_부터 씨가 쓰여진 아래의 칼럼으로 해 보겠습니다

[Elixir] 키워드 목록의 키로 처리를 변경하는 예
htps : // 이 m/더러운_에서/있어 ms/364b75f1cd8d28df6272

덧붙여 「Elixir ZEN Style」에 대해서는, 아래의 칼럼을 봐 주세요

Elixir Zen 스타일 프로그래밍 강좌
htps : // 코 m / 쟈키 1972 / ms / 619f39 c77f b52b1 bf

이 칼럼의 검증 환경



본 칼럼은, 이하 환경에서 검증하고 있습니다(Windows에서 실시하고 있습니다만, Linux나 mac에서도 동작한다고 가정합니다)
  • Windows 10
  • Elixir 1.10.1    ※ 최신 버전의 설치 절차는 여기

  • 키워드 목록의 키로 로직 전환



    키워드 리스트의 key마다, 다른 처리를 실행할 수 있는 전환을, 등록이 끝난 key의 리스트와, 함수의 가드로 실현하고 있는 것이, 전 칼럼의 내용입니다

    모듈의 "@ 변수"에 키 목록을 등록하고 가드 "in"에서 목록과 일치합니다.
    defmodule ArgumentsSample do
    
      @spec sample(Keyword.t) :: any
      def sample(kw) do
        keys = Keyword.keys(kw)
        values = Keyword.values(kw)
    
        IO.puts "Start..."
        sample(keys, values)
      end
    
      @match1 [:hoge, :huge]
      @match2 [:foo, :bar]
    
      defp sample([key|keys_tail], [value|values_tail]) when key in @match1 do
        IO.puts "@match1 match"
        IO.puts "#{key} = #{value}"
        sample(keys_tail, values_tail)
      end
    
      defp sample([key|keys_tail], [value|values_tail]) when key in @match2 do
        IO.puts "@match2 match"
        IO.puts "#{key} = #{value}"
        sample(keys_tail, values_tail)
      end
    
      defp sample(key, value) do
        IO.puts "...End"
      end
    end
    

    실행 결과는 다음과 같습니다.
    iex> ArgumentsSample.sample hoge: 1, foo: 2, bar: 3, hoge: 4, huge: 5
    Start...
    @match1 match
    hoge = 1
    @match2 match
    foo = 2
    @match2 match
    bar = 3
    @match1 match
    hoge = 4
    @match1 match
    huge = 5
    ...End
    :ok
    

    원래 코드가 재귀로 구현되는 곳을 Enum.each에서 Elixir ZEN Style화합니다.
    defmodule ArgumentsSample do
    
      @spec sample( Keyword.t ) :: any
      def sample( kw ) when is_list( kw ) do
        IO.puts "Start..."
        kw |> Enum.each( & sample( &1 ) )
        IO.puts "...End"
      end
    
      @match1 [ :hoge, :huge ]
      @match2 [ :foo,  :bar  ]
    
      def sample( { key, value } ) when key in @match1 do
        IO.puts "@match1 match"
        IO.puts "#{ key } = #{ value }"
      end
      def sample( { key, value } ) when key in @match2 do
        IO.puts "@match2 match"
        IO.puts "#{ key } = #{ value }"
      end
    end
    

    실행 결과는 변하지 않고 동일한 결과가 출력됩니다.

    다시 쓰기 포인트


  • 재귀로 인한 흐름 제어를 제거하여 각 샘플에서 흐름 제어를 제거하고 목록 분할을 제거했습니다
  • 이로 인해 키와 값을 미리 검색하는 중간 처리가 더 이상 필요하지 않습니다
  • 마지막 메시지 출력을 재귀의 종단(≒빈 리스트)로서 마지막 sample에서 하고 있었지만, 메인측에 옮길 수 있었습니다

  • 효과


  • 코드 행 수를 30% 줄일 수 있습니다.
  • 제어 흐름과 처리 분할로 전망이 향상되었습니다

  • 이 기법의 사용점



    소위 「Strategy 패턴」이나 「State 패턴」과 같은, 입력이나 상태에 의해, 핸들러를 스위치 하는 것과 같은 것이면, 이 테크닉에 의해, 매우 보수성이 높고, 전망이 좋은 코드가 됩니다(일일이 클래스 을 만드는 우자함도 Elixir이므로 당연하지 않습니다)

    키워드 리스트에 입력이나 상태를 늘어놓고, 핸들러를 부르는 key 마다 그룹핑을 실시하면 OK입니다

    덧붙여 각 리스트에 key가 단수 밖에 없는 경우는, 아래와 같이, 함수 패턴 매치로서 직접 쓰면 좋기 때문에, in에 의한 가드도, 「@변수」의 등록도, 불필요하게 됩니다
    
      def sample( { :hoge, value } ) do
        IO.puts "@match1 match"
        IO.puts "#{ key } = #{ value }"
      end
      def sample( { :foo, value } ) do
        IO.puts "@match2 match"
        IO.puts "#{ key } = #{ value }"
      end
    
    

    그건 그렇고 ...



    가드의 "in"지정이 "@ 변수"가 아니면 오류가 발생합니다.

    이것은 이상한 사양과 같이 보입니다만, 가드에 쓸 수 있는 구문에는, 비교적 제약이 있다(동적인 함수나 자기 정의 함수는 우선 사용할 수 없다) 때문에, 하는 방법은 없습니다

    아마도 ``@variables''는 컴파일 타임에 상수이기 때문에이 제약에 걸리지 않을 것입니다.

    p.s.「좋아요」 잘 부탁드립니다



    페이지 왼쪽 상단의 또는 을 클릭해 주셔서 감사합니다
    여기의 숫자가 늘어나면, 필자로서는 「우케하고 있다」라는 감각을 얻을 수 있어 연재를 더욱 진화시켜 나가는 동기 부여가 되기 때문에, 보다 Elixir 재료를 보고 싶다고 하는 당신, 저희와 함께 북돋워 제발!

    좋은 웹페이지 즐겨찾기