TIL: if 와 loop 안쓰고 코딩하기 with elixir

sam·2023년 11월 2일

Elixir

목록 보기
4/7
post-thumbnail

오늘의 문제


bird-count

반복문을 recursive function으로 접근하는 법을 연습했다.
recursive function은 자신을 다시 호출하는 함수이다.
느낌이 안좋다. 왜냐하면 잘못했다간 무한루프로 가서 진짜 stack overflow에러를 만나게 되기 때문이다.

하지만 함수형언어에서는 반복문을 recursive function 으로 구현한다. 아래와 같이 두 경우로 나눠서 구현하면 된다.

  1. base case - 반환 값이 값(value) 형태인 함수, 함수를 호출하지 않는다!
  2. recursive case - 함수를 다시 호출 하는 경우. 하지만 호출할때 넘기는 argument는 언젠가 base case 로 갈 수 있어야한다.

아래와 같이 한큐에 모든 테스트를 다 통과해서 엄청 뿌듯한 마음으로 우쭐했다.
recursive function은 아래의 total/1 함수이다.

  • base case - def total([]), do: 0
  • recursive case - def total([head | tail]), do: head + total(tail)
defmodule BirdCount do
  def today([head | _]), do: head
  def today([]), do: nil
    
  def increment_day_count([head | tail]), do: [head + 1 | tail]
  def increment_day_count([]), do: [1]
  def has_day_without_birds?([head | tail]) do
    if head === 0 do 
      true
    else has_day_without_birds?(tail)
    end
  end
  def has_day_without_birds?([]), do: false
    
  def total([head | tail]), do: head + total(tail)  
  def total([]), do: 0
  def busy_days([head | tail]) do
    if head > 4 do
      1 + busy_days(tail)
    else busy_days(tail)
    end
  end
  def busy_days([]), do: 0
end

pul 선생님의 solution!

바로 솔루션 비교해보자

defmodule BirdCount do
  @count_on_busy_day 5

  def today([]), do: nil
  def today([todays_count | _ ]), do: todays_count

  def increment_day_count([]), do: [1]
  def increment_day_count([todays_count | previous]), do: [todays_count+1 | previous]

  def has_day_without_birds?([0 | _]), do: true
  def has_day_without_birds?([]), do: false
  def has_day_without_birds?([_ | previous]), do: has_day_without_birds?( previous)

  def total([]), do: 0
  def total([count | previous]), do: count + total(previous)

  def busy_days([]), do: 0
  def busy_days([count | previous]) when count >= @count_on_busy_day,
    do: 1 + busy_days(previous)
  def busy_days([_ | previous]), do: busy_days(previous)

end

역시 선생님의 코드는 훌륭하다.👏👏👏👏

  • def today([todays_count | _ ]), do: todays_count 패턴매칭에서 도메인 의미가 담긴 argument 이름짓기. 사실 처음에 나도 today 라고 넣었다가 today()/1함수랑 이름이 같아져서 도메인 의미를 제거한 head라는 이름을 넣었다. 좀더 생각했으면 좋았을껄..
  • if 를 안쓰고 모두 guard패턴 매칭으로 해결하고있다.
    • 관심사가 tail 인 경우 -> def has_day_without_birds?([_ | previous]), do: has_day_without_birds?( previous)
    • 관심사가 head = 0 인 경우 -> def has_day_without_birds?([0 | _]), do: true
    • 가드로 표현식을 넣음
  • 상수를 정의할때 @로 표현할 수 있구나! (약간 pl/sql 느낌이다. when 문도 그렇고 sql 작성할 때와 비슷한 결이 느껴진다)

💡 if 없이 최대한 한줄로 간결하게 작성하기
💡 함수명 뒤에 xxxx? 붙으면 결과값이 boolean 값이다.

profile
다이조부

0개의 댓글