fork download
  1. type request = string * string * string (* リクエスト. 銘柄id,期間from,期間toの三つ組 *)
  2. ;;
  3. let code (c,_,_) = c
  4.  
  5. type quote = { price:int; } (* 銘柄の値段.実際には、他にも多くの情報が含まれている *)
  6. ;;
  7.  
  8. type response = {
  9. req: request; (* どのリクエストに対するレスポンスか *)
  10. body: quote; (* レスポンスの内容 *)
  11. seq:int; (* レスポンス中、何番目のメッセージか *)
  12. total:int; (* 応答メッセージの総数 *)
  13. }
  14. ;;
  15.  
  16. (* 受信途中のレスポンスのバッファを次の連想テーブル(Map)で構成する。
  17.   OCamlのMapは、キーの型と比較関数をMap.Makeに渡せば得られる *)
  18. module M = Map.Make (
  19. struct
  20. type t = request (* リクエスト型をキーとして *)
  21. let compare = Pervasives.compare (* 何か適当に比較してもらう *)
  22. end)
  23. ;;
  24.  
  25. (* レスポンスを保持するバッファ。 一息で書いたのでやたら複雑な型だが、
  26.   リクエストをキー(上記)として、受信途中のレスポンスをペア (int * quote option array) で保持する。
  27.   このペアは (受信済みメッセージ数, 銘柄データの配列) という意味だ。
  28.   - 未受信のメッセージをNoneで埋めておきたいがため option 型の配列になっている。
  29.   - 同じキーをもつ複数のレスポンスを同時に扱う格納するため、リストにしてある。
  30.   - グローバル変数なのは醜いけれど、クロージャに入れればすぐになんとかなる
  31. *)
  32. let buf : (int * quote option array) list M.t ref = ref M.empty
  33. ;;
  34.  
  35. (* 株価のリストをデータベースに保存する. ダミーで画面への出力関数にしてある *)
  36. let save (code:string) (quotes:quote option list) : unit =
  37. print_string (code ^ " ");
  38. List.iter begin function
  39. | Some q -> Printf.printf "%d;" q.price
  40. | None -> failwith "impossible"
  41. end quotes;
  42. ;;
  43.  
  44. (*
  45.   メッセージrをバッファに格納する。 レスポンス全体が得られたら、saveで保存する。
  46. *)
  47. let receive_quote (r:response) : unit =
  48. if r.total=1 then save (code r.req) [Some r.body] (* 総レコードが1件のみであればすぐに保存 *)
  49. else begin
  50. let map = !buf in
  51. (* このリクエストに対するレスポンスのリスト(更新前) *)
  52. let all = try M.find r.req map with Not_found -> [] in
  53.  
  54. (* バッファに新しいレスポンスを追加 *)
  55. let newentry () =
  56. let arr = Array.make r.total None in (* レスポンス全体をNoneで初期化 *)
  57. arr.(r.seq) <- Some r.body;
  58. buf := M.add r.req ((1, arr)::all) map (* 1つ受信しましたよとバッファを更新 *)
  59. in
  60.  
  61. (* レスポンスのリストを走査し適切な位置に格納 / レスポンス全体が満たされたら保存 *)
  62. let rec addentry rest = function
  63. | [] -> newentry () (* 受信ずみレスポンスなし. 新しいレスポンスを追加する *)
  64. | (cnt, arr) as y::ys -> (* 受信ずみレスポンスあり *)
  65. match arr.(r.seq) with (* 当該の連番は受信済みか *)
  66. | None ->
  67. arr.(r.seq) <- Some r.body; (* レスポンスの該当する連番を満たす *)
  68. if cnt+1=r.total then begin
  69. (* レスポンス全体が満たされた. 保存後、この配列をバッファから除く *)
  70. save (code r.req) (Array.to_list arr) (* 保存 *);
  71. buf := M.add r.req (List.rev_append rest ys) map (* yの削除によりバッファを更新 *)
  72. end else
  73. (* また足りない.受信済み数をインクリメントしバッファを更新 *)
  74. buf := M.add r.req (List.rev_append rest ((cnt+1, arr)::ys)) map
  75. | Some q -> (* このレスポンスでは格納済み. 次のレスポンスを見る *)
  76. addentry (y::rest) ys
  77. in
  78. addentry [] all
  79. end
  80. ;;
  81.  
  82.  
  83. let test =
  84. let a="A","1","4" and b = "B","1","2" in
  85. let resps = [
  86. {req=a; body={price=1100}; total=4; seq=0};
  87. {req=a; body={price=1098}; total=4; seq=1};
  88. {req=a; body={price=1100}; total=4; seq=0};
  89. {req=b; body={price=910}; total=2; seq=0};
  90. {req=a; body={price=1098}; total=4; seq=1};
  91. {req=a; body={price=1081}; total=4; seq=2};
  92. {req=a; body={price=1081}; total=4; seq=2};
  93. {req=a; body={price=1120}; total=4; seq=3};
  94. {req=b; body={price=940}; total=2; seq=1};
  95. {req=a; body={price=1120}; total=4; seq=3};
  96. ] in
  97. List.iter receive_quote resps
  98.  
Success #stdin #stdout 0.01s 2736KB
stdin
Standard input is empty
stdout
A 1100;1098;1081;1120;
B 910;940;
A 1100;1098;1081;1120;