スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#雑記 ゴミ収集日カレンダーを作る

ごみの収集カレンダーを簡易表示するプログラムを作ってみました。
テーマは関数の「部分適用」と「関数のリスト」と「関数のリストをList.foldで利用する」です。
 
実行例
> showGCalendar 2010 5;;
 
2010年5月のごみの収集カレンダー
 
  1日(土) :: 
  2日(日) :: 
  3日(月) :: 
  4日(火) ::  可燃ゴミ
  5日(水) ::  ペットボトル
  6日(木) :: 
  7日(金) ::  可燃ゴミ プラ
以下略 
 
 
年度と月からその月の日数を求めるのはDateTime.DaysInMonth メソッドを利用します。

> DateTime.DaysInMonth (2010,4);;
val it : int = 30
 
曜日にはDateTime.DayOfWeek プロパティを利用します。
例えばDayOfWeek.Sundayで日曜日を表します。 
 
まずは次のような関数を定義してみます。
 
> let mkAddStr (d:DayOfWeek) (nthLst:list<int>) (str :string) (in_d:DayOfWeek) (in_nth:int)=
    if (d = in_d && (List.tryFind (fun e -> e = in_nth) nthLst) <> None ) then 
        (fun state -> state + " " + str) 
    else
        (fun state -> state);;
 
val mkAddStr :
  DayOfWeek -> int list -> string -> DayOfWeek -> int -> (string -> string)
 
引数は曜日1、第何週リスト、追加する文字、曜日2、第何週で
曜日1と曜日2が一致し、かつ第何週が第何週リストに含まれている場合は
「引数の文字列に対してstrを連結した文字列を返す関数 」
それ以外の場合は
「引数の文字列そのままを返す関数 」を返します。
 
例として毎週火曜日は「可燃ごみ」という条件を上の関数に部分適用してみます。
(毎週は第1週から第5週までに含まれるという条件に言い換えます)
 

 > let test0 = mkAddStr DayOfWeek.Tuesday [1 .. 5] "可燃ゴミ";;
 
val test0 : (DayOfWeek -> int -> string -> string)
 
このtest0 に更に実際の曜日と第何曜日かを渡すと、「条件が合えば"可燃ゴミ"を追加し、合わないときはそのままの文字列を返す」関数が得られます。

 
条件が合えば文字列を変化させます。
> let changeStr0 = test0 DayOfWeek.Tuesday 2;; //第2火曜日
val changeStr0 : (string -> string)
 
> changeStr0 "";;
val it : string = " 可燃ゴミ"
 
条件に合わないものを渡すと文字列を変化させません。
> let changeStr1 = test0 DayOfWeek.Sunday 3;; //第3日曜日
val changeStr1 : (string -> string)
 
> changeStr1 "";;
val it : string = ""
 
さて、具体的条件を部分適用した関数のリストを作ります。
 
> let mkAddStrLst =
    [mkAddStr DayOfWeek.Tuesday   [1 .. 5] "可燃ゴミ";
     mkAddStr DayOfWeek.Friday    [1 .. 5] "可燃ゴミ";
     mkAddStr DayOfWeek.Friday    [1;2;4]  "プラ";
     mkAddStr DayOfWeek.Friday    [3] "紙";
     mkAddStr DayOfWeek.Wednesday [1] "ペットボトル";
     mkAddStr DayOfWeek.Wednesday [2] "空き瓶";
     mkAddStr DayOfWeek.Wednesday [3] "不燃ゴミ";
     mkAddStr DayOfWeek.Wednesday [4] "缶"];;
 
val mkAddStrLst : (DayOfWeek -> int -> string -> string) list =
  [<fun:mkAddStrLst@15-8>; <fun:mkAddStrLst@16-9>; <fun:mkAddStrLst@17-10>;
   <fun:mkAddStrLst@18-11>; <fun:mkAddStrLst@19-12>; <fun:mkAddStrLst@20-13>;
   <fun:mkAddStrLst@21-14>; <fun:mkAddStrLst@22-15>]
 
これらの関数を次々に具体的特定の「曜日」と「第何週か」に適用していく関数を定義します。
 
> let applyFuncs (in_d:DayOfWeek) (in_nth:int) =
    List.fold  (fun s f -> f in_d in_nth s)  "" mkAddStrLst;;
 
val applyFuncs : DayOfWeek -> int -> string
 
条件に合えば、文字が追加され累積されます。

> applyFuncs DayOfWeek.Friday 1;;
val it : string = " 可燃ゴミ プラ"
> applyFuncs DayOfWeek.Friday 3;;
val it : string = " 可燃ゴミ 紙"
> applyFuncs DayOfWeek.Tuesday 3;;
val it : string = " 可燃ゴミ"
> applyFuncs DayOfWeek.Sunday 3;;
val it : string = ""
 
次に曜日を日本語で表示する関数を定義しておきます。
 
let dow2j (d:DayOfWeek) =
    match d with
    | DayOfWeek.Sunday    -> "(日)"
    | DayOfWeek.Monday    -> "(月)"
    | DayOfWeek.Tuesday   -> "(火)"
    | DayOfWeek.Wednesday -> "(水)"
    | DayOfWeek.Thursday  -> "(木)"
    | DayOfWeek.Friday    -> "(金)"
    | DayOfWeek.Saturday  -> "(土)"
    | _ -> ""
 
 
あとはこれをmap関数で一日一日に適用します。
表示前のデータを作る関数は次のようになります。
> let mkEveryDayLst year month =
    let daysInMonth = DateTime.DaysInMonth (year,month) //月の日数
    let dayWeek = List.map (fun i -> 
                                let d = new DateTime(year,month,i)
                                let dow = d.DayOfWeek //曜日
                                let nth = (i-1)/7+1   //第何週か
                                (i,
                                 dow2j(d.DayOfWeek),
                                 applyFuncs dow nth))
                            [for i in 1 .. daysInMonth -> i]
    dayWeek;;
 
val mkEveryDayLst : int -> int -> (int * string * string) list
 
使ってみます。
 
> mkEveryDayLst 2010 4;;
val it : (int * string * string) list =
  [(1, "(木)", ""); (2, "(金)", " 可燃ゴミ プラ"); (3, "(土)", ""); (4, "(日)", "");
   (5, "(月)", ""); (6, "(火)", " 可燃ゴミ"); (7, "(水)", " ペットボトル"); (8, "(木)", "");
   (9, "(金)", " 可燃ゴミ プラ"); (10, "(土)", ""); (11, "(日)", ""); (12, "(月)", "");
   (13, "(火)", " 可燃ゴミ"); (14, "(水)", " 空き瓶"); (15, "(木)", "");
   (16, "(金)", " 可燃ゴミ 紙"); (17, "(土)", ""); (18, "(日)", ""); (19, "(月)", "");
   (20, "(火)", " 可燃ゴミ"); (21, "(水)", " 不燃ゴミ"); (22, "(木)", "");
   (23, "(金)", " 可燃ゴミ プラ"); (24, "(土)", ""); (25, "(日)", ""); (26, "(月)", "");
   (27, "(火)", " 可燃ゴミ"); (28, "(水)", " 缶"); (29, "(木)", "");
   (30, "(金)", " 可燃ゴミ")]
   
   
最後にまとめて表示する関数を作ります。
 
> let showGCalendar year month =
    let gLst = mkEveryDayLst year month
    printf "\n%d年%d月のごみの収集カレンダー\n\n" year month
    List.iter (fun (d,wod,gar) -> printf " %2d日%s :: %s\n" d wod gar) gLst ;;
 
val showGCalendar : int -> int -> unit
 
使ってみます。
> showGCalendar 2010 4;;
 
2010年4月のごみの収集カレンダー
 
  1日(木) :: 
  2日(金) ::  可燃ゴミ プラ
  3日(土) :: 
  4日(日) :: 
  5日(月) :: 
  6日(火) ::  可燃ゴミ
  7日(水) ::  ペットボトル
  8日(木) :: 
  9日(金) ::  可燃ゴミ プラ
 10日(土) :: 
 11日(日) :: 
 12日(月) :: 
 13日(火) ::  可燃ゴミ
 14日(水) ::  空き瓶
 15日(木) :: 
 16日(金) ::  可燃ゴミ 紙
 17日(土) :: 
 18日(日) :: 
 19日(月) :: 
 20日(火) ::  可燃ゴミ
 21日(水) ::  不燃ゴミ
 22日(木) :: 
 23日(金) ::  可燃ゴミ プラ
 24日(土) :: 
 25日(日) :: 
 26日(月) :: 
 27日(火) ::  可燃ゴミ
 28日(水) ::  缶
 29日(木) :: 
 30日(金) ::  可燃ゴミ
val it : unit = ()
 
全コードは次の通りになります。
open System
 
let mkAddStr (d:DayOfWeek) (nthLst:list<int>) (str :string) (in_d:DayOfWeek) (in_nth:int)=
    if (d = in_d && (List.tryFind (fun e -> e = in_nth) nthLst) <> None ) then 
        (fun state -> state + " " + str) 
    else
        (fun state -> state)
 
let mkAddStrLst =
    [mkAddStr DayOfWeek.Tuesday   [1 .. 5] "可燃ゴミ";
     mkAddStr DayOfWeek.Friday    [1 .. 5] "可燃ゴミ";
     mkAddStr DayOfWeek.Friday    [1;2;4]  "プラ";
     mkAddStr DayOfWeek.Friday    [3] "紙";
     mkAddStr DayOfWeek.Wednesday [1] "ペットボトル";
     mkAddStr DayOfWeek.Wednesday [2] "空き瓶";
     mkAddStr DayOfWeek.Wednesday [3] "不燃ゴミ";
     mkAddStr DayOfWeek.Wednesday [4] "缶"]
 
let applyFuncs (in_d:DayOfWeek) (in_nth:int) =
    List.fold  (fun s f -> f in_d in_nth s)  "" mkAddStrLst
 
let dow2j (d:DayOfWeek) =
    match d with
    | DayOfWeek.Sunday    -> "(日)"
    | DayOfWeek.Monday    -> "(月)"
    | DayOfWeek.Tuesday   -> "(火)"
    | DayOfWeek.Wednesday -> "(水)"
    | DayOfWeek.Thursday  -> "(木)"
    | DayOfWeek.Friday    -> "(金)"
    | DayOfWeek.Saturday  -> "(土)"
    | _ -> ""
 
let mkEveryDayLst year month =
    let daysInMonth = DateTime.DaysInMonth (year,month) //月の日数
    let dayWeek = List.map (fun i -> 
                                let d = new DateTime(year,month,i)
                                let dow = d.DayOfWeek //曜日
                                let nth = (i-1)/7+1   //第何週か
                                (i,
                                 dow2j(d.DayOfWeek),
                                 applyFuncs dow nth))
                            [for i in 1 .. daysInMonth -> i]
    dayWeek
 
let showGCalendar year month =
    let gLst = mkEveryDayLst year month
    printf "\n%d年%d月のごみの収集カレンダー\n\n" year month
    List.iter (fun (d,wod,gar) -> printf " %2d日%s :: %s\n" d wod gar) gLst 
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。