0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

「バス代」をErlangで(横へな9)

Last updated at Posted at 2013-07-04

http://nabetani.sakura.ne.jp/hena/ord9busfare/
「バス代」をErlangでやってみました。

  • 大人、子供、幼児の料金を別々に計算して合計しています。
  • 幼児は1人ずつ料金を求め、金額が高い方から大人×2人分を削除しています。
  • 年齢区分、料金区分はそれぞれ大人料金からの割合として格納し、料金計算の時に掛け合わせています。例: Cw→子供(0.5)×福祉割引(0.5)→大人料金の0.25倍

1関数1行で書いたらどうなるだろうと思ってやってみました。(一応、すべての行が80桁以内になっています。)

いままで再帰を使うときは頭の中で手続き的なループを考えていました。今回は1行で書くため再帰すら使わず、ループが必要なときはmap, filter, foldlなどに関数を渡し、ひたすら大きな関数を小さな関数に分割することでプログラムを作成しました。手続き型だった脳が、少しずつ関数型に慣れてきたように思います。

なお、1関数1行はトップダウンで書くと書きやすかったですが、はたして読みやすいのかどうか?

bus.erl
-module(bus).
-compile(export_all).

solve(Data) -> adult_fee(Data) + child_fee(Data) + infant_fee(Data).

adult_fee(Data) -> lists:sum(fees($A, Data)).

child_fee(Data) -> lists:sum(fees($C, Data)).

infant_fee(Data) -> lists:sum(dropn(num_adult(Data) * 2, rev_sort(fees($I, Data)))).

num_adult(Data) -> length(fees($A, Data)).

fees(Mark, Data) -> [mark_to_fee(X, base_fee(Data)) || X <- only(Mark, Data)].

mark_to_fee(Mark, BaseFee) -> roundup10(marks_to_ratio(Mark) * BaseFee).

roundup10(X) -> trunc(X / 10 + 0.99) * 10.

marks_to_ratio(Marks) -> lists:foldl(fun(X, S) -> mark_to_ratio(X) * S end, 1, Marks).

mark_to_ratio(Mark) -> element(2, find_mark(Mark)).

find_mark(Mark) -> hd(lists:dropwhile(fun({M, _}) -> M =/= Mark end, ratio_data())).

ratio_data() -> [{$A, 1}, {$C, 0.5}, {$I, 0.5}, {$n, 1}, {$p, 0}, {$w, 0.5}].

base_fee(Data) -> list_to_integer(hd(string:tokens(Data, ":"))).

only(Mark, Data) -> lists:filter(fun(X) -> hd(X) =:= Mark end, marks(Data)).

marks(Data) -> string:tokens(lists:nth(2, string:tokens(Data, ":")), ",").

dropn(N, L) -> case length(L) >= N of true -> lists:nthtail(N, L); false -> [] end.

rev_sort(L) -> lists:reverse(lists:sort(L)).

tests() ->
  test("210:Cn,In,Iw,Ap,Iw", 170), %0
  test("220:Cp,In", 110), %1
  test("440:In,Ip,Cp,Aw,Iw,In,An", 660), %39
  test("1270:Ap,In,An,Ip,In,Ip,Ip", 1270). %40

test(Data, Expected) ->
  Result = solve(Data),
  OkNg = case Result =:= Expected of true -> ok; false -> ng end,
  io:fwrite("~s: ~s -> ~w~n", [OkNg, Data, Result]).
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?