Elmをやってみたログ

前から気になっていたのでやってみた。
疑問はあまり解決しないまま。

まずはエディタの設定。
`elm-mode`に加えて`flycheck`や`elm-oracle`、`lsp-mode`などを試してみたけど動かない。


仕方がないので取り敢えず`elm-mode`だけでやってみた。
`C-c C-c`はダメっぽい。
https://emacs.stackexchange.com/questions/50479/elm-mode-cant-compile-file
色々大きく変更する必要があるっぽい。

`C-c C-l`はファイル名と場所を正しくすれば動くけど、アクティブウィンドウが切り替わるのが使いづらい。


https://emacs.stackexchange.com/questions/7409/is-there-a-generic-toggle-previous-window-function
ここに書いてある設定を使って

```elisp
(defun switch-to-last-window ()
  (interactive)
  (let ((win (get-mru-window t t t)))
    (unless win (error "Last window not found."))
    (let ((frame (window-frame win)))
      (raise-frame frame)
      (select-frame frame)
      (select-window win))))

(defun elm-repl-load-back ()
  (interactive)
  (elm-repl-load)
  (switch-to-last-window)
  )

(require 'elm-mode)
(add-hook 'elm-mode-hook
          (lambda ()
            ;; (elm-format-on-save-mode)
            (local-set-key (kbd "C-c C-l") 'elm-repl-load-back)
            ))
```

こんな感じにして、`C-c C-l`でアクティブウィンドウを切り替えないようにした。もっと単純な設定がある気がするが。

マニュアルを見ながら書いていく。

```elm
main =
  Browser.element
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }


init = undefined
view = undefined
update = undefined
subscriptions = undefined
```

というようにまずはコンパイルを通すようにして`C-c C-l`をカチカチしながら進めたいんだけど、`Elm`だとundefinedが無い？少しずつ書くにはどうしたらいいんだろう。

分からないのでそれも置いておいて、 https://github.com/evancz/elm-architecture-tutorial この辺を適当にいじってみる。


https://qiita.com/arowM/items/dfb38d1c5f3dfde8b8bf
この辺を読んでいると、どうも合ってない気がするが…。HTMLは普通にファイルで書きたいので、The Elm Architecture じゃなくなるよね。


例えば `Closure Tools`を使いつつ

```javascript
goog.provide('app.main');

goog.require('goog.dom');
goog.require('ElmJs');

function runQ(){
  var q = window['q'] || [];
  for (var i = 0; i < q.length; i++){
    q[i]();
  }
  window['q'] = {
    push: function(f){
      f();
    }
  };
}

function runApp()
{
  var el = goog.dom.getElement('elm');
  console.log(el);

  var app = window['Elm']['Main']['init']({
    node: document.getElementById('elm')
  });

}

window['runApp'] = runApp;
runQ();
```

こんな感じにしたい。`Closure Compiler`でまとめて圧縮しても一応動くけど、HTMLはサーバーサイドで書いたものをそのまま使いたいんだよなー…。



ていうわけで
https://qiita.com/ymtszw/items/d195c098445476527539
この辺を参考にしつつ

```elm
port module Main exposing (..)

import Platform
import Task
import Time
import Json.Encode as Encode
import Time.Extra

main =
    Platform.worker
        { init = init
        , update = update
        , subscriptions = subscriptions
        }


-- MODEL


type alias Model =
  { zone : Time.Zone
  , time : Time.Posix
  }


init : () -> (Model, Cmd Msg)
init _ =
  ( Model Time.utc (Time.millisToPosix 0)
  , Task.perform AdjustTimeZone Time.here
  )



-- UPDATE


type Msg
  = Tick Time.Posix
  | AdjustTimeZone Time.Zone



dateToStr : Model -> String
dateToStr model =
    let
        hour =
            String.fromInt (Time.toHour model.zone model.time)
        minute =
            String.fromInt (Time.toMinute model.zone model.time)
        second =
            String.fromInt (Time.toSecond model.zone model.time)
    in
        hour ++ ":" ++ minute ++ ":" ++ second



update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Tick newTime ->
        let newmodel = { model | time = newTime }
        in
            ( newmodel
            , sender (Encode.string <| dateToStr newmodel)
            )

    AdjustTimeZone newZone ->
        let newmodel = { model | zone = newZone }
        in
            ( newmodel
            , sender (Encode.string <| dateToStr newmodel)
            )



-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
  Time.every 1000 Tick

port sender : Encode.Value -> Cmd msg
```


```html
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="UTF-8">
  <title>Main</title>
  <script src="main.js"></script>
</head>

<body>
  <h1>test</h1>
  <div id="elm"></div>
  <script>
    var app = Elm.Main.init();
    app.ports.sender.subscribe(
      function(a){
        document.getElementById('elm').innerHTML = a;
      }
    );
  </script>
</body>
</html>
```

こんなコードをテストしてみたり。

検索して出てくる`Platform.program`が`worker`に変わった？
動くけど、こんな使い方をしていいものかどうか。


理想は
https://qiita.com/arowM/items/6c32db1f9e4b92445f3b
ここに書いてあるようなパーサー等を使いつつ、HTMLやCSSは普通に別ファイルで書きたい。
https://n314.hatenablog.com/entry/20110824/1314182177 昔自分がScalaで書いたやつ。こんな感じにタグのclassやnameを読み取って自動でバインディングしたい。
可能かどうかで言えば可能な気がするし他の言語でやるよりやりやすい気がするけど、用途がズレているのが気になる。


あと気になるのが、PHPでParsecを書いたときは超遅くなってメモリも大量に使ったんだけど、JavaScriptは大丈夫なのかね。
トランスパイル時に良い感じに最適化してくれるんかな。