「は」制作で感動したこと

え? こんなことある?
と今感動してゐるので 忘れないうちに 書いておかうと思つた

今まで エディタのやうなものを制作しやうとして ゴチャゴチャやってきた經驗はあつた
基本的にjavascriptでやってゐたのだが 例へば
行が左端に達したら スクロールする といふ処理を書くのに 色々試行錯誤した記憶がある
イメージをコピーして ずらした位置にペーストするやうなことをやってゐた

今回 Haskellで エディタのやうなものを制作してゐるのだが
なんと このスクロール処理が 単にパラメータを引いたりしただけで實現できてしまつた
具體的には

makePicOsds :: [[Int]] -> [Float] -> State -> [Picture]
makePicOsds numList line st = 
  let txOsds = map (\ls -> map ((!!) (osds st)) (map abs ls)) numList
   in concat $ zipWith (\txos ln -> zipWith (\(Just t) (x,y) ->
        translate (startX-shiftX*x) (startY-shiftY*y) $ scale fScale fScale $ t)
                      txos [(a,b)|a<-[ln..],b<-[0..(_by st)]]) txOsds line

上のコードを

makePicOsds :: [[Int]] -> [Float] -> State -> [Picture]
makePicOsds numList line st = 
  let txOsds = map (\ls -> map ((!!) (osds st)) (map abs ls)) numList
   in concat $ zipWith (\txos ln -> zipWith (\(Just t) (x,y) ->
        translate (startX-shiftX*x) (startY-shiftY*y) $ scale fScale fScale $ t)
                      txos [(a,b)|a<-[(ln-_sx st)..],b<-[0..(_by st)]]) txOsds line

このやうにしただけだ

變はつたのは 一番下の行の ln のところが (ln-_sx st) になっただけである
スクロールするぶんだけ 表示行の初期位置をずらした といふだけで
スクロールが實現できてしまつた

もちろん Haskellでなくても 同じやうなアルゴリズムを用ひてゐれば
同様にできるのだらう
しかし このやうなことが出來ることに氣付かせてくれたのは 私にとつては
確實にHaskellである

もちろん カーソルの移動によるスクロール値の變化や
文章挿入時の処理に若干變更をしてゐるが ほとんど上のやうなレベルである
少なくとも 切つたり貼つたりといふ 新しい函數を作ることは 全くしなかつた
さう! javascriptでは 必ず スクロール処理の函數を書いてゐたものだ

断言したい
Haskell は 私にとつて 偉大な 師匠である!!

「は」 制作 覺へ書き

ここには 自分が コーディングで つまづいたり 悩んだりしたことを含め 今後の制作の參考になるやう 解決策などを記したいと思つてゐる

テキストの挿入

もともとあるテキストの途中に 一文字挿入する という エディタでは當り前にある機能を實装するのに とても悩んだ
一回頭がぐちゃぐちゃになつて 中断し 好きなゲームとかをして 次の日の朝 じっくり取り組み
何とか 次のやうなコードを得た

addTxt :: Char -> State -> State
addTxt ch st = 
  let txs = lines (_tx st) 
      lns = lineStartX (_by st) txs 
      lnInfo = getLn 0 (_x st) lns
      lnNum = fst lnInfo
      newTxs = if lnNum>(-1)
        then
          let ln = txs !! lnNum
              txPos = getPosition (_by st) (_x st) (_y st)
                 (fst$snd lnInfo) (snd$snd lnInfo) ln 
              ltNum = fst txPos
              sp = take (snd txPos) (repeat ' ')
              newLn = (take ltNum ln)++sp++[ch]++(drop ltNum ln) 
           in (take lnNum txs)++[newLn]++(drop (lnNum+1) txs)
        else
          let blankLines = take (round (_x st - (last lns))) (repeat [])
              sp = take (round (_y st)) (repeat ' ')
           in txs++blankLines++[sp++[ch]]
      (nx,ny)= if (_y st)<(_by st) then (_x st,_y st+1) else (_x st+1,0)
   in st {_tx = unlines newTxs, _x = nx, _y = ny, _md=1}

lineStartX :: Float -> [[a]] -> [Float]
lineStartX by list = foldl (\acc ls -> acc++[(last acc +
              (if (length ls>0) then fromIntegral
                    (ceiling $ (fromIntegral (length ls))/(by+1))
                                else 1))]) [0] list 

getLn :: Int -> Float -> [Float] -> (Int,(Float,Float))
getLn _ _ (y:[]) = ((-1),(y,y+1))
getLn i x (y:z:ys) =
  if (x>=y && x<z) then (i,(y,z))
                   else getLn (i+1) x (z:ys)

getPosition :: Float -> Float -> Float -> Float -> Float -> [a] -> (Int,Int)
getPosition by x y x0 x1 ls =
  let lastLetters = fromIntegral (length ls) - (by+1)*(x-x0) 
   in if (x==(x1-1)) && lastLetters<y
          then (length ls,round (y-lastLetters))
          else (round ((by+1)*(x-x0)+y),0)

大まかな手順としては

  • 全體のテキストを一行づつに分ける (lines (_tx st))
  • 分けたものが 表示行として何行目から始まるのか示すリストをつくる (lineStartX)
  • カーソルのx位置に対応する文章(最初に分けたテキストの一行分)を特定し それが何行目と何行目の間にあるかを得る(getLn)
  • 上で カーソルのx位置が 表示されてゐる文の左側にあり どのテキストにも對應してゐない場合 (-1)が返されてゐる
  • 一文(テキストの一行分)が特定されてゐれば カーソルのx,yの位置に對應する 文章(Char型のリスト)の位置を特定する(getPosition)
  • 特定された場合 そこに挿入しやうとしてゐる文字を挿入し 全體のテキストを形作つていく
  • 文章の末尾から離れたところに カーソルのx, y座標があつた場合 そこまで空白や行を挿入し その後に文字を挿入して 全體のテキストをつくる

できたのは こんな感じのものである

www.nicovideo.jp

細かいエラーは 實行してみて直すのだが
とりあへずビルドに成功するのが目標だった
ひとつひとつ 考へやすい部分に問題を細分化していつて
簡單に實現できるところから 實装していくやうにした

まず 明確な目標をもつた
カーソルの位置を 複數行あるテキストの位置と對應させるには どうしたらよいか
これを實現しなければならない といふ 明確な目的意識である
これがある限り
「いつかは實現できる」
といふ確信が生まれる
もし そのときできなければ よく寝て 再び考へればよいのだ

とにかく 多くのことを 一度に意識して処理しやうとすると
頭が混亂して 「こんなん できるか!」
となる

「この目標を達成するために 一番簡單で すぐに出來ることは何か?」
といふのを 常に意識して取り組んだつもりだ

まう少し具体的に言ふと 仮に頭の中で 今カーソルが差し示してゐるx,y座標と テキストのリストの位置とを 同時に思ひ浮べてみる
なんかすごい大天才であれば それを処理して すぐに函數を書いたりできるのかもしれないが
少くとも 私はそんな 頭が良くはない
だから そんなふうに考へたら すぐに頭の中はオーバーヒートしてしまひ うへぇ~となつて 倒れてしまふ
だから 一度に多くのことを 処理しやうとしてはいけない

「まづ 文章のリストの何番目に 現在のカーソルが對應するのか それを特定することはできないか?」
これが とりあへずの目標となる
「そのためには 文章のリストが それぞれ 表示行の何行目から始まつてゐるのか 知らなければならない」
となる
ならば
「それを知るには どうしたらよいか」
これが 新しい目標となる

最初の目標など これをクリアするまで 忘れていいし 忘れた方がいい(でも 何か目標があった といふことだけは覺へておく)

ちなみに このコードを書くにあたつて 「空白行をどうするか」とか「空きスペースをどうするか」といふ問題は
全く後回しにした
正直 最初ビルドが成功したときには 「どうせ思つた通りには行かない筈」
と考へ 「問題が起きたところで コードを見て手直しすればいい」
くらゐに考へてをり 實際かなりうまく動いたので驚いたくらいだ

つまり コードの挙動の細部まで 全部理解できてゐなくても コードが一應エラーなくビルドできてしまへば
實行して結果を見てから対策を立てても良いのではないかと思ふ
これは もしかしたら 函數型コーディングの利點のひとつではないだらうか

常に變數の動きを意識しながら命令していかねばならないコーディングの場合
そのコードの挙動について完全に理解し 予測しなければ 實行時に必ずバグが出て
しかも そのバグの所在が分からない といつた事態になりさうだが
Haskellは さういふことが少ないのではないか と直感的に思ふ
まあ 私は命令型だらうが 函數型だらうが プロフェッショナルではないので 言ひ切ることは全くできないが

とにかく 目標が達成されたときの喜びは 何といふか 天にも昇る心地といふか
(そのまま昇天したら困るが)
とても嬉しい

しかし 道程はまだまだ長い
私にとつて ゴールは 恐れ多くて口で言へないほど 挑戰的である
どっかに書いたかもしれないが(笑)

最大公約數とjavascriptとブラックホール

最大公約數(gcd) を求める函數 gcd

'use strict';
const tgcd = (i1,i2,ci,dv,rs) => {
  if(i1>=i2){
    if(i1%ci==0){return ci;}else{
      if(i2%dv==0){
        if(i1%dv==0){return tgcd(i1,i2,parseInt(i2/dv),dv+1,dv)}
        else{return tgcd(i1,i2,parseInt(i2/dv),dv+1,rs)}}
      else{if(dv<i2/dv){return tgcd(i1,i2,ci,dv+1,rs)}else{return rs;}}}
  }else{return tgcd (i2,i1,i1,dv,rs);}
}
const gcd = (i1,i2) => {return tgcd(i1,i2,i2,2,1);}

分數の計算をするにあたつて 最大公約數を求める必要があると感じ
ネットを検索して調べたのだが 「再歸でやると 大きい數ではできない」
などと書かれてゐて 「ほんとかな?」と思ひ 實装してみた

手順:
  • i1とi2を比べ 大きい方をi1 小さい方をi2 とする
  • ciにi2をセット
  • i1をciで割り切れれば ciが最大公約數
    さもなくば i2を2(dvの値)で割つてみて 割り切れるなら その値をciとし
  • i1をciで割る
    同時にdvでもi1を割り 割り切れたらrs=dv(この場合は2)とする
    i1をciで割つたとき 割り切れれば ciが最大公約數となるが
    割りきれなければ こんどはi2を3(次のdv)で割つてみて 割りきれたら その値をciとし
  • i1をciで割る
    このやうに i2を2,3,4,5...で割り 割り切れた商でi2が割れれば その商を最大公約數 としてゐる
  • i2を2,3,4,5...で割つたときの商が 割る數(dv)よりも大きければ そこで計算を止め
    これら 割る數のうちで i1を割り切れてゐたもの(rs)を 最大公約數とする
結果:

8桁の整数同士までは エラーが出ずに計算できた
また 一方が10桁で他方が6桁などの場合もエラーは出なかつた
しかし 9桁の整数同士くらゐになると
RangeError: Maximum call stack size exceeded
のエラーとなる

これは javascriptを処理するプログラムが「末尾再歸呼び出しの最適化」の機能を持つてゐないことによる とされ
昔のNode(javascriptを實行するアプリのひとつ)では--harmonyといふオプションで對應できてゐたが 最近のバージョンでは
その機能が削除された といふ
webブラウザも當然 javascriptを實行するアプリだが ほとんど「末尾再歸呼び出し」には對應してゐないらしい

考察:

ネット上に この事に關する記事が少なく 自分はまだ全然分かつてゐない状態だ
これは 落ち込むと抜け出せなくなるタイプの話題にみえるので これ以上あまり深入りしないことにする
こんなふうに アリ地獄のごとく 人の精神を食いものにする話題が 巷にはあふれてゐる
ブラックホールもそのひとつ
ブラックホール見付かったんだって! すごいね!」
で 終はりにできる幸せな人が ちょっと羨しく思へる
これを考へ出したら最後 精神は深く大きな暗黒の世界へと 飲み込まれていく
例へば 私は 現在定義されたやうなブラックホールが存在しない と思つてゐるが
それは 私の達したある種の合理的結論であるとともに
私の精神を ブラックホールの手前で何とか保持する手段でもある
私が この存在を認めたが最後 それを証明するために
私は その基礎だけで百科事典ほどもある 複雑な數式で書かれた一般相對性理論の世界を彷徨ふことになるのだ

人から いくら無力だ 勉強不足だと思はれても 私は構はない
私には ある種の 信念 ある種の 直感がある
それは 大きく穴をあけて 知的好奇心を食おうとしてゐるやうな存在から 素早く 逃げることである!

シンプルな思考でも 何かを實らせることができる
單純に考へても 實現したかつたことが 達成できる
偉い人が強調するブラックホールを拒絶しても きっと生きていける
私はさう信じてゐる

Haskell + OpenGL の可能性

目的が簡單に成就するなんて さうさうない

大きな山の手前に 小さいけれど 美しい山があつたので登つてみた

さういふことだと 理解してゐる

 

歴史ゲームを創つてみたいと 思つた

Haskellで グラフィカルな部分を ほとんど考へずに

コンソールのテキスト表示だけ

入力はキーボードだけ BGMなし

それでも 面白いと自分が感じられるものを

 

自動でマップをランダムに作成したり

ファイルから文章を讀み込み表示させたり

選択肢を選んで 正解すると イベントが變化したり

さういつたことが實現でき

さらに敵とのエンカウントが成功して

いよいよ戰鬪の實装だ といふときに

 

別のことにハマってしまつた

 

私が所属してゐる塾で 子供達との會話の中から

ヒントを得て 何とか試してみやう と思つたこと

それは 「エーテル」をシミュレートできないか といふものだ

 

エーテル」とは有機化學における「エーテル」ではなく

天文學において 一時期 考案されてゐたもので

光を傳へる媒質 であるが

マイケルソン・モーリーなどの實驗によつて 存在が否定された とされるものである

 

私は 若干の文献にあたり 若干の考察をした結果

理由は述べないが 「エーテル」は存在するのではないか と思つてゐる

そして つい最近まで 「エーテル」のモデルを

ボールに バネがくっついたやうなもの

と考へてゐた

宇宙空間に 原子よりもずっと小さいレベルの玉があつて

それらが お互ひに 何らかの弾性力によつて結びつき

常に振動してゐるのではないか と

 

今では (それこそ 「エーテル」をシュミレートしやうとしてゐる今となつては)

次のやうに考へてゐる

ボールは となりのボールと直接くっついてはゐないが

ボール同士が離れやうとすると 引っぱられ

あまり近づかうとすると 引き放される

つまり両者の間にバネがあるかのやうな挙動をする

ボール同士は ある程度の距離をもつと もはや近づかうともせず

なめらかに 自由に動くこともできる

 

何日か 試行錯誤し  Haskellを使つて

ボールとバネのモデルをつくり 一次元の(一直線上にならぶ)

ボールとバネが バネの長さの變化によつて どのやうな挙動を示すか

實驗してみた

何とか 結果が出たところで やはり これを直感的に見える形にしやう

といふことで Hasteを使ひ

ボールがバネの力によつて動くのを 目で見えるやうにした

 

その後 二次元の(縦方向と横方向のそれぞれにボールが並ぶ)モデルをつくり

函數を設定して バグに悩まされながらも 何とかそれらしきものができたので

ブラウザ上に表現した

http://syouzan.sakura.ne.jp/

 

しかし これは ボールの個數が多くなるにつれ メモリをかなり壓迫してしまふ

私のディスクトップパソコンの場合 ボールを100個にしてシミュレートすると

途中で動作が止まつてしまふこともあつた

Haste は Haskellコードから javascriptを生成し ブラウザで動作させるために

使ふものと理解してゐる

實行ファイル 何とか.exe によつて グラフィックをそのまま表示させるものではない

 

といふところで 脳裏に浮かぶのは

OpenGL

だった

 

Haskellのコードから OpenGLを使ふ 簡單なサンプルコードを試してみたことがあつた

私としては ここに表示されてゐるやうな  ごく普通のフォントを

OpenGLを使つて Haskellのコードで表示させたりしたかつたのだが

どうしても やり方が分からず 断念してゐた

HaskellSDLを使ひ すごい かっこいいゲームを創つた方がゐて

http://questro.jp/blog/lightit-history/

SDL やつてみたかつたのだが

どうしても導入時のエラーが解決できず 断念した

 

しかし 今私がやつてゐるシミュレーションは

OpenGLなら 結構簡單に實装できるのではないか

と思ひ それなりに チャカチャカやってゐたら

できた

github.com

多重リストをマップしなければならないところで

うまく行くか心配だつたが

動いたので 良かつた

これを進めていくと さらに色々なことが出来さうな氣がしてゐる

 

これでフォントが普通に表示できる方法が分かれば

さらに モチベーションが上がるんだけど・・・

 

しかし ほどほどのところで 歴史ゲーム制作にも戻つていきたい

 

 

こと

自分で プログラミング言語を創りたい

なんてことは 別の言語(例へば Cとか Javaとか)の達人にでもならなければ 口に出すべきでないのかも知れない

しかし 私は それを ここで言ふ

きっと それは 不完全なものだらうし 未熟なものだらう

そもそも 私は 他の言語を使ひこなしてゐない

下手くそな javascript で やっとこさ ゲームらしきものを創りあげた程度である

 

けれども 私には 動機がある

ただ なんとなく 創つてみたい といふわけでもない

 

私の心の中には ある種の ゴールがある

この言語が どのやうな形になるか といふ ゴールだ

しかし それは ここで言ひたくない

それを まさに 形にしてから 説明できると良いと思ふ

 

この構想は ずっと以前から あった

しかし 本格的に 形にしていかう と動き出してゐるのは 今年になつてからだと思ふ

 

この言語で 何かを動かすための 第一歩として

ターミナルから起動する インライン計算機のやうなものを作成してゐる

 

Bashシェルスクリプトにより Haskellコードをコンパイルした實行ファイルを起動

これによつて 入力した文字列を Haskellコードに變換してゐる

そのコードの文字列を ghcプログラムに渡し モジュールをインポートした状態で實行させ 最後に出力された結果に對し 形を少々變換させて ターミナルへ書き出してゐる

 

github.comこの インライン入力プログラムを 「ことは」 と名付けた

Haskellで書かれた メインプログラムである Conv.hs も

ghc -e で實行時に 讀み込まれる Func.hs も 私なりの問題解決法を含んでをり

それなりに話題となり得るが

今回特に 強調したいのは シェルスクリプトである kotoha.sh における

history 機能である

はっきり言つて この機能が無くても 自分の目指す目的が全く叶わないわけでもないし

計算機能自体には あまり關係がないので

全く實現できなかつたとしても それなりに諦めがつく機能ではあつた

しかし やはり コマンドを入力した後に 上矢印キーを押すと 前回の履歴が表示されたりするのは プロンプトを扱ふ上では 日常的にやることであり

こいつが無いと やはり少し 寂しい氣がするのだつた

 

しかし ネットを色々検索しつつ この機能の實装について調べても

何だか良く分からず とにかく色々と命令を追加して 實驗を繰り返し

やっとのことで 實現できた結果が このコードなのである

 

#!/bin/bash

set -o histexpand
set -o vi
history -r "history.txt"
echo "*** Kotoha Inline Coder *** 2019/3/1 yokoP"

while :
do
read -e -p "> " line
if [ "${line}" = "exit" -o "${line}" = "q" ]; then
break
fi
./Conv "${line}" | cat | while read tx; do\
echo ${tx:1:-2}; ghc -e "${tx:1:-2}" | cat |\
while read rs; do rs="${rs:0:-1}"; rs=${rs// % //};\
rs=${rs%/1}; rs=${rs///1]/]}; rs=${rs///1,/,}; rs=${rs//,/, };\
echo ${rs}; done; done
echo $line >> "history.txt"
history -n "history.txt"
done

exit 0

 

この 履歴といふ機能に關はる部分は 最初の方の

set -o histexpand
set -o vi
history -r "history.txt"

と 最後の方の

echo $line >> "history.txt"
history -n "history.txt"

といふところだ

set -o vi または set -o emacs などとすることによつて

文章の編集方式を指定してゐるが

これがないと 上矢印キーを押したとき

カーソルがプロンプトの部分より上に行つてしまふと同時に

エスケープキャラクターが入力されたことになってしまひ

Enterを押したときに このキャラクターが變數へと讀みこまれてしまつて

當然入力の解釈ができなくなつてしまふ

編集方式が指定されることにより この挙動は抑制されるやうなのだ

しかし そのままだと  矢印キー(上)を押しても 何も反應がない状態となる

これはこれで害はないのだが やはり履歴機能をつけたい

といふことで

set -o histexpand

としてゐる

この設定法も 試行錯誤でみつけたもので ネット上で調べても 全く分からなかつた

ちなみに これを

set -o history

としてしまふと 履歴の挙動は おかしくなる

原因は不明だが 何故か シェルスクリプトそのものを履歴として格納しだすのだ

 

履歴ファイル history.txt といふのを作業フォルダにつくり

入力された文字列を 變數 line に格納して それを履歴ファイルへ書き出す

といふ形を取つてゐる (historyコマンドを使ふ方法は うまく行かなかつた)

このファイルヘ書き込むと同時に そのファイルから新しいものを讀み込んでゐるのが

history -n "history.txt"

の部分である

これをやることで 入力して結果を出し 次のプロンプトが出たとき

上矢印キーで 直前の入力をそのまま表示することに成功した

履歴を削除したければ history.txt を編集すれば濟むことだ

今のところ とても快適に機能してゐる

Haste でいけるのか

すこし頭が痛い

今 なんとか Haskellコードをベースにして ブラウザ上に サーバーから読み込んだテキストを表示させることに成功した

まう 無理だらう と 何度思つたことか

GHCJSを入れやうとして 少なくとも 10パターンくらゐの試みは すべて 失敗に終はつた

qiita.com

web上で このGHCJSを扱つたページがいくつかあったが 本當に どうやつて インストールしてゐるのだらうか

github.com

さすがに 根負けした といふか  今のところは GHCJSが より一般的になつて 誰でもインストールできるやうになるのを待つしかない と思つてゐる

Hasteは ほとんど更新もされてゐないやうで gitリポジトリのReadMeは 3年前のものだ

github.com

それでも Haste自體 windowsに簡單インストールでき

GHC7.10.2を用意しさへすれば (これも かなり古いバージョンに戻ることになるのだが) hastecコマンドが機能する

 

コードは次のやうになつた

github.com

{-# LANGUAGE OverloadedStrings #-}
import Haste
import Haste.Graphics.Canvas
import Haste.Foreign

textfile :: String
textfile = "kotonoha.txt"

startX :: Double
startX = 400

startY :: Double
startY = 100

main :: IO ()
main = do
    Just can <- getCanvasById "canvas"
    tx <- readFromFile textfile
    view can tx

view :: Canvas -> String -> IO ()
view can tx = do
    render can $ do
       lineWidth 2.0 $ do
           color (RGB 255 255 255) $ stroke $ rect (0,0) (450,700)
           mapM_ (color (RGBA 255 255 255 0.8) . font "24px oshide") $ letterList tx
    return ()

letterList :: String -> [Picture ()]
letterList ts = do
    zipWith text (zip [a*b | a <- [startX,(startX-40)..], b <- take 14 (repeat 1)]
          (map (+startY) $ cycle [30,60..(30*14)])) (map (\c -> c : []) ts)

readFromFile :: String -> IO String
readFromFile = ffi "(function(fname){var text=null; var ajax=new XMLHttpRequest(); /*@if(1) ajax.onreadystatechange @else@*/ ajax.onload /*@end@*/ = function(){ (ajax.readyState==4)&&(ajax.status==200)&&(text=ajax.responseText);}; ajax.open('GET',fname,false); ajax.send(null); return text;})"

 

 

ajaxを使はず コードの中にテキストを埋め込んでしまへば

readFromFileは必要ない

それはそれで 文章の縦書き化が このHasteで實現できたときは 結構感動したのだが

やはりajaxは難解だつた

結局 Haste.Ajax モジュールの使用はあきらめ (使ひ方がまるで分からない)

javascriptのコードを埋め込むために Haste.Foreign モジュールを利用した

しかしまた そのjavasciptコードがうまく動かず 失敗續きで まうやめやう と思つてゐた時に 単純なスペルミスが發覺し 何とか 期待してゐた動作まで辿りつくことができた

 

Elmでなく Haskellにどうしてもこだはりたい理由が 上の letterList 函數にある

たったこれだけの記述で 文字列から一文字づつ取り出して 座標を與へ 縦書きのためのリストを生成するのである

Haskell初心者の私に このやうなコードを書かせてくれる Haskellといふ言語の魔力に どうやら 取りつかれてしまつたらしい

くり返しを何回にするか決めて 變數を使ひ 決まつた數だけくり返す

のではなく

無限のリストをつくり その中から必要なだけ取り出す

のである

 

とにかく スタートラインに立つてゐるやうな氣分になつてゐる

この方面に詳しい人から見れば 全くバカげたことかもしれないが

これが學びに繋がることは確實である

また 行けるところまで 行かうとおもふ

Elm

Elmで書いたアプリを公開したい

たった これだけのことを サクっと説明する記事が 見あたらなかった

例へば Elmに關心があって そのホームページからElmをインストールし 丁寧に解説されてゐるチュートリアルを讀んで 簡單なコードを書く

そして ブラウザ上で そのコードを實行する

すごい!

Elmは オンラインでコードを組むこともできるし 様々なサンンプルコードを實行させることができる

ホントすごい!

・・・・

で 公開するには どうしたら?

おそらく 多くの人が

「そんなん 言はんでも わかるがな! おぬしアホかいな!」

と言つて 相手にしないのだらう

だから その具體的な説明がなされてゐない

 

javascriptのコードをサーバー上で實行させるなら

自分は 次のやうにすれば動くことを知つてゐた

 

index.htmlをつくる

たとへば 下記のやうな

 

***************index.html***********************

<!DOCTYPE HTML>
<head>
<title>TEST</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<script type="text/javascript" src=test.js" charset="utf-8"></script>
</head>
<body onLoad="load();">
</body>
</html>

**************************************************

これで test.js の load関数が實行される

index.html と test.js がサーバー上の同じディレクトリにアップされてゐれば

對應するurlへアクセスすることで コードが實行されるだらう

 

Elmで同じやうなことをするには どうするか

まづ ターミナルで 次のやうにして Elmコードから elm.jsファイルをつくる

$ elm make test.elm --optimize --output=elm.js

これは 本家の解説にも出てゐることだが この場合 htmlファイルのみ生成されてゐる

 

つくられたhtmlファイルを見ると コードが ボワーーっと大量に書かれてゐた

これでも公開できるのだが jsファイルをつくって色々やりたい!

その方が絶對すっきりするもん! といふことで その場合のhtmlファイルが どうかけるか 下に記す

 

***********index.html*************************

<!DOCTYPE HTML>
<head>
<title>ELM TEST</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<div id="elm"></div>
<script type "text/javascript" src="elm.js" charset="utf-8"></script>
<script>
var app = Elm.Main.init({ node: document.getElementById('elm') })
</script>
</body>
</html>

*************************************************

 

コンパイルしてできた elm.js と このindex.htmlを 同じディレクトリに置いて (ディレクトリを變へたいなら src= の部分を變へればよい) index.htmlにアクセスすれば動くはずだ

main函數を含む elmコードに モジュール名をつけた場合は

var app = Elm.モジュール名.init({ node: document.getElementById('elm')})

となる筈だ

<div id="elm"> の elmと

getElementById('elm') の elm は同じである必要がある

ただの名前なので

<div id="ほげ">

getElementById('ほげ')

でも動く

elm.js (これだって 名前はなんでもよい) は さらに最適化 最小化できる

そのためのツールは 色々あるだらう

htmlファイルだけで濟ませやうとすると ファイルが大きくなったとき 高速化や 最適化をするのに 都合が惡いと思ふし なんといふか

美しくない!!

 

htmlファイルと jsファイルを 上のやうに生成してやれば

もちろん サーバーにアップしなくても htmlファイルをそのまま實行して

ローカルにブラウザ上で動作を確認することだってできる

(もちろんこれは  elm reactor でなされてゐることではあるが)

 

自分にとって これが解決したことで Elmへの敷居がずっと低くなった

これから どっぷりとElm ワールドにハマっていかうと思つてゐる