Exericsm에서 Elixir로 Freeleancer Rates 를 풀게 되었는데 이를 기록하기 위해 작성한다.
문제
In this exercise you'll be writing code to help a freelancer communicate with a project manager by providing a few utilities to quickly calculate daily and monthly rates, optionally with a given discount.
We first establish a few rules between the freelancer and the project manager:
•
The daily rate is 8 times the hourly rate.
•
A month has 22 billable days.
Sometimes, the freelancer is offering to apply a discount on their daily rate (for example for their most loyal customers or for non-for-profit customers).
Discounts are modeled as fractional numbers representing percentage, for example 25.0 (25%).
Calculate the daily rate given an hourly rate
Freelancer의 일급을 계산하는 문제이다.
•
하루 8시간
•
반환 Double
def daily_rate(hourly_rate) do
hourly_rate * 8.0
end
Elixir
복사
Calculate a discounted price
앞선 instruction의 설명과 같이 비영리단체, 충성도 높은 고객을 위한 discount를 적용한다.
def apply_discount(before_discount, discount) do
before_discount * (100 - discount) / 100
end
Elixir
복사
|> 을 연습하는중 이기 때문에 원활하게 변경이 되지 않으니 최초 값을 만들고 리팩토링 해보자.
def apply_discount(before_discount, discount) do
before_discount
|> Kernel.*(100 - discount)
|> Kernel./(100)
end
Elixir
복사
Kernel 을 사용하여 |> 적용하기
Elixir의 Kernel 이란 무엇인가?
Java, Kotlin 에서 java.lang 패키지와 유사한 역할을 수행한다.
Elixir의 기본 함수와 연산자들을 제공하는 모듈로 import 가 없더라도 모든 Elixir 에서 사용할 수 있다.
모든 모듈에서 공통적으로 사용할 수 있기 때문에 Kernel. 이라는 prefix는 생략한다.
Kernel 모듈의 주요 기능
•
산술 연산자: +, -, *, / 등 기본적인 산술 연산을 제공한다.
•
비교 연산자: ==. !=, <, >, <=, >= 등의 비교 연산을 제공한다.
•
제어 구조: if, unless, case, cond 등 조건문과 제어 구조를 제공한다.
•
기타 기본 함수: 함수 호출(apply), 익명 함수(fn), 리스트 처리(Enum 모듈을 통해), 맵 처리(Map 모듈을 통해) 등 다양한 기본 함수를 제공한다.
혹시 다음과 같은 사용이 가능한지 궁금했었다.
def apply_discount(before_discount, discount) do
before_discount
|> *(100 - discount)
|> /(100)
end
Elixir
복사
잘못된 예시 이런거 elixir에 없다.
|> 은 앞의 output을 받아 다음의 첫 번째 argument 에 input으로 할당한다.
Calculate the monthly rate, given an hourly rate and discount
•
한 달 치 급여를 계산한다.
•
Instruction 에서 확인해보면 한 달을 22일(business day)로 계산하는 것을 확인할 수 있다.
•
hourly_rate, discount 를 argument로 받는다.
•
소수점을 올림하여 Integer 로 반환해야 한다.
def monthly_rate(hourly_rate, discount) do
rate = apply_discount(daily_rate(hourly_rate) * 22, discount)
rate = Float.ceil(rate)
rate = trunc(rate)
end
Elixir
복사
처음에 작성한 코드 |> 가 아직 익숙하지 않다.
Float.ceil/1 (올림)
이 함수는 주어진 부동 소수점 숫자를 올림하여 가장 가까운 정수를 반환한다.
수학적인 올림 함수로, 주어진 숫자보다 크거나 같은 가장 작은 정수를 반환한다.
iex> Float.ceil(3.14)
4.0
iex> Float.ceil(7.2)
8.0
Elixir
복사
Float.floor/2 (내림)
Float.floor/2 는 주어진 부동 소수점 숫자를 내림하여 가장 가까운 정수를 반환한다.
iex> Float.floor(3.14)
3.0
iex> Float.floor(7.8)
7.0
Elixir
복사
Float.round/2 (반올림)
Float.round/2 함수는 주어진 부동 소수점 숫자를 지정된 소수점 이하 자리수까지 반올림하여 반환한다.
소수점 이하 자리수를 지정하지 않으면 기본값은 0이다.
iex> Float.round(3.14159, 2)
3.14
iex> Float.round(7.856, 1)
7.9
iex> Float.round(7.856)
8.0
Elixir
복사
trunc/1 (버림)
Kernel.trunc/1 함수는 부동 소수점 숫자의 소수점 이하를 버리고 정수 부분만 반환합니다.
iex> trunc(3.14)
3
iex> trunc(7.8)
7
Elixir
복사
이러한 개념을 바탕으로 아래와 같이 리팩토링 한다.
def monthly_rate(hourly_rate, discount) do
hourly_rate
|> daily_rate
|> Kernel.*(22)
|> apply_discount(discount)
|> Float.ceil()
|> trunc
end
Elixir
복사
Calculate the number of workdays given a budget, hourly rate and discount
주어진 budget과 hourly rate, discount로 얼마나 오랫동안 급여를 줄 수 있는지 계산하는 함수를 만든다.
def days_in_budget(budget, hourly_rate, discount) do
Float.floor(budget / (monthly_rate(hourly_rate, discount)/22), 1)
end
Elixir
복사
이 함수는 아래와 같이 |> 를 사용했다.
def days_in_budget(budget, hourly_rate, discount) do
daily = hourly_rate
|> monthly_rate(discount)
|> Kernel./(22)
budget / daily
|> Float.floor(1)
end
Elixir
복사
그런데 daily 라는 변수를 만들지 않는다면 아래와 같이 만들 수 있을것 이다.
def days_in_budget(budget, hourly_rate, discount) do
budget
|> Kernel./(monthly_rate(hourly_rate, discount) / 22)
|> Float.floor(1)
end
Elixir
복사
뭐가 더 elixir 컨벤션에 맞는 코드인지는 elixir에 대한 경험치가 더 쌓여야 할 것 같다.
필자는 daily 를 선언하는 것으로 일단 마무리 짓겠다.
결과적으로 완성된 코드는 아래와 같다.
defmodule FreelancerRates do
def daily_rate(hourly_rate) do
hourly_rate * 8.0
end
def apply_discount(before_discount, discount) do
before_discount
|> Kernel.*(100 - discount)
|> Kernel./(100)
end
def monthly_rate(hourly_rate, discount) do
hourly_rate
|> daily_rate
|> Kernel.*(22)
|> apply_discount(discount)
|> Float.ceil()
|> trunc
end
def days_in_budget(budget, hourly_rate, discount) do
budget
|> Kernel./(monthly_rate(hourly_rate, discount) / 22)
|> Float.floor(1)
end
end
Elixir
복사