2016年5月21日土曜日

Done

ご指名ではないけど久々に書いてみました。OCamlもJSも詳しくないので細かいことは知らない。(追記:入力消すの忘れてたので修正。)(追記2:「状態渡し」すら不要だからしなかったんですけど、どうしても状態渡しを使わないと納得しない人がいるようなので使いました。)

DoNe

    module H = Dom_html
    let g x = Js.Opt.get x (fun () -> assert false)
    let o = Js.Opt.return
    let s = Js.string
    
    let _ = H.window##onload <- H.handler (fun _ ->
      Firebug.console##debug (s "DoNe starting");
      let d = H.document in
      let tm = g (d##getElementById (s "todo_time")) in
      ignore
        (H.window##setInterval
           (Js.wrap_callback (fun _ ->
             tm##textContent <- o (jsnew Js.date_now ()##toString ())),
            100.));
      let txt = g (H.CoerceTo.input (g (d##getElementById (s "todo_text")))) in
      let btn = g (H.CoerceTo.input (g (d##getElementById (s "todo_button")))) in
      let ul = g (d##getElementById (s "todo_ul")) in
      btn##onclick <- H.handler (fun _ ->
        let v = txt##value in
        Firebug.console##debug (s ("DoNe adding: " ^ Js.to_string v));
        let li = H.createLi d in
        li##textContent <- o v;
        Dom.appendChild ul li;
        btn##value <- s ("NewDoNe#" ^ string_of_int (1 + ul##childNodes##length));
        txt##value <- s "";
        Js._false);
      Js._false)
    
    • 今回は「状態渡し」すら要らないので「お絵かき」より簡単。何をさせたかったのかまったくわからない。どうしても状態渡しを使え、というならば以下のとおり。
      module H = Dom_html
      let g x = Js.Opt.get x (fun () -> assert false)
      let o = Js.Opt.return
      let s = Js.string
      
      let _ = H.window##onload <- H.handler (fun _ ->
        Firebug.console##debug (s "DoNe starting");
        let d = H.document in
        let tm = g (d##getElementById (s "todo_time")) in
        ignore
          (H.window##setInterval
             (Js.wrap_callback (fun _ ->
               tm##textContent <- o (jsnew Js.date_now ()##toString ())),
              100.));
        let txt = g (H.CoerceTo.input (g (d##getElementById (s "todo_text")))) in
        let btn = g (H.CoerceTo.input (g (d##getElementById (s "todo_button")))) in
        let ul = g (d##getElementById (s "todo_ul")) in
        let rec handler items = (fun _ ->
          let v = txt##value in
          let new_items = items @ [v] in
          Firebug.console##debug (s ("DoNe adding: " ^ Js.to_string v));
          let li = H.createLi d in
          li##textContent <- o v;
          Dom.appendChild ul li;
          btn##value <- s ("NewDoNe#" ^ string_of_int (1 + List.length new_items));
          txt##value <- s "";
          btn##onclick <- H.handler (handler new_items);
          Js._false) in
        btn##onclick <- H.handler (handler []);
        Js._false)
      
    • すでに別の人も指摘しているとおり、以前の「状態渡し」のほうがOCaml上のGUIアプリの実装としては異常。書けないとか言うから反例として書いただけ。OCamlは非純粋関数型なので、普通は副作用(破壊的代入を含む)を使う。FRPを含め、純粋関数型のGUIプログラミングがしたかったらHaskellのライブラリなりElmなり、それ用の適切な道具を使えば良い。
    • 自分から要求した「お絵かき」の「トイプログラム」すら1年もかかって自称FRP(実際にはFunctionalですらない命令型プログラム。哲学とか時刻とか理屈をこねたり過去の値を保存したところで、ユーザから見て命令型の非単一代入であることに何ら変わりはない。ちなみにtimeengine.jsの保存のしかただと通常のFRPと異なりたとえ「過去の値」が不要になってもJS処理系がガベコレできないのでメモリリークします。)でしか書けないのに、また他人に実装を要求する正当性は1ミリもない。

    0 件のコメント:

    コメントを投稿