Purescript
Haskellの記事を色々見て復習してたんだ。オイラーの脳内メモリーはDRAMですよ。 常にリフレッシュしないと蒸発しちゃうからね。
ついこの間も一般人が見るような所に、記事が載ってたぞ。 Haskell こういうのをきっかけに、数学に再トライするのもよかろう。Pythonばかりが数学を 解く道具じゃないからね。多様性は善、進化に必要。
そう言えば、図書館の新刊コーナーに置いてあった、 『工学部ヒラノ教授のはじまりの場所』 (今野浩)っての、面白かったな。シリーズに なってるようなので、色々借りてこよう。(wikipediaからのリンクでも色々読めて面白いぞ)
で、とある人がHaskell似のPureScriptってのがいいよって叫んでいた。ちょいと箸休めで 箸を伸ばしてみるかな。資料は、下記ぐらい。
A strongly-typed functional programming language that compiles to JavaScript
PureScript Advent Calendar 2016
どこの陣地に入れる? PureScriptってのは、Haskell似のスクリプトをコンパイルしてJavascriptにするらしい。ならば、Web系に強い ClearLinuxが良かろう。 バンドルを探ってみたら、上手い具合に nodejs-basicってのが有った。こいつを入れるだけで、npmとかいうパッケージマネージャが使えるのかな? 悩むより手を動かせ。
sakae@clr:~$ node -v v7.10.0 sakae@clr:~$ npm install purescript > purescript@0.11.5 postinstall /home/sakae/node_modules/purescript > node lib/install.js The `/home/sakae/node_modules/purescript/vendor/purs` binary doesn't seem to work correctly pre-build test failed compiling from source built successfully /home/sakae └─┬ purescript@0.11.5 ├─┬ bin-build@2.2.0 : └── to-executable-name@1.1.0 npm WARN enoent ENOENT: no such file or directory, open '/home/sakae/package.json' npm WARN sakae No description npm WARN sakae No repository field. npm WARN sakae No README data npm WARN sakae No license field.
コンパイルに随分時間がかかる(30分ぐらい)と思ったら、haskell君が裏で健闘してたぞ。
sakae@clr:~$ ps aocmd node lib/install.js stack install --allow-different-user --local-bin-path /home/sakae/node_modules/p /home/sakae/.stack/setup-exe-cache/x86_64-linux-tinfo6/setup-Simple-Cabal-1.24.2 /home/sakae/.stack/programs/x86_64-linux/ghc-tinfo6-8.0.2/lib/ghc-8.0.2/bin/ghc ps aocmd
続いて、PureScript用のパッケージを取り寄せるためのプログラム(pythonで言うpip)を インストールします。難しい事は無く、npm install bower するだけみたい。 これで、取り合えずの用意が出来たんで、node_modules/.bin/ にPATHを通しておきます。
それから、何はなくともハロワです。適当なdirを作ってその中で作業するという、世間一般に 言われてるプロジェクトなるものを作ります。大げさ自慢だな。
sakae@clr:~/hello$ bower install --save purescript-console bower cached https://github.com/purescript/purescript-console.git#3.0.0 bower validate 3.0.0 against https://github.com/purescript/purescript-console.git#* : purescript-prelude#3.1.0 bower_components/purescript-prelude sakae@clr:~/hello$ mkdir src sakae@clr:~/hello$ cat -- > src/Main.purs module Main where import Prelude import Control.Monad.Eff (Eff) import Control.Monad.Eff.Console (CONSOLE, log) main :: Eff (console :: CONSOLE) Unit main = log "Hello, world!" Ctl+D ;;コピペの終了を指示
purescript-consoleってのが、出力用のパッケージだそうな。こういう基本的なやつも コンパイラーとは別になってるとな。
続いて、src-dirを作り、Webからのスクリプトを貼り込みます。なんか、Haskellのそれと 似てますなあ。
sakae@clr:~/hello$ purs compile "bower_components/purescript-*/src/**/*.purs" "src/**/*.purs" Compiling Data.Show Compiling Data.NaturalTransformation Compiling Data.Boolean : Compiling Prelude Compiling Control.Monad.Eff.Class Compiling Main
コンパイルの成果物は、outputの中に置かれるとな。
sakae@clr:~/hello$ ls output/ Control.Applicative Data.BooleanAlgebra Data.Ordering Control.Apply Data.Bounded Data.Ord.Unsafe Control.Bind Data.CommutativeRing Data.Ring Control.Category Data.DivisionRing Data.Semigroup Control.Monad Data.Eq Data.Semiring Control.Monad.Eff Data.EuclideanRing Data.Show Control.Monad.Eff.Class Data.Field Data.Unit Control.Monad.Eff.Console Data.Function Data.Void Control.Monad.Eff.Uncurried Data.Functor Main Control.Monad.Eff.Unsafe Data.HeytingAlgebra Prelude Control.Semigroupoid Data.NaturalTransformation Data.Boolean Data.Ord
目指すはMainの中に出来たindex.js それをNode環境で走らせる。
sakae@clr:~/hello$ node > const Main = require('./output/Main/index') undefined > Main.main() Hello, world! {}
これが基本の流れみたいだ。オイラーが嬉しいと思うのは、Haskellなんかに比べて小ぶりな パッケージが揃っている事。
Pursuit is the home of PureScript documentation
bodil/pulp
先の例だと、自分でプロジェクトdirを作ったけど、そしてコンパイルも面倒だった。で、面倒 嫌いな現代人用に誰かが苦労し、その分け前が公開されてる。
pulpを入れた時点での関係者達
sakae@clr:~$ npm list --depth 0 /home/sakae ├── bower@1.8.0 ├── pulp@11.0.0 └── purescript@0.11.5 sakae@clr:~$ ls node_modules/.bin/ acorn find-versions pulp static bin-version-check insert-module-globals purs strip-dirs bower JSONStream rc strip-indent browserify lpad-align rimraf tree-kill browserifyinc miller-rabin seek-bunzip umd browser-pack mime seek-table which deps-sort mkdirp semver executable module-deps sha.js
早速、使ってみる。
sakae@clr:/tmp$ mkdir hoge sakae@clr:/tmp$ cd hoge/ sakae@clr:/tmp/hoge$ pulp init : purescript-psci-support#3.0.0 bower_components/purescript-psci-support └── purescript-console#3.0.0 sakae@clr:/tmp/hoge$ pulp run : Compiling Main Compiling PSCI.Support * Build successful. Hello sailor!
これで終わりにしようかと思ったけど、pulpのgithubを見てたら、簡単にWebから 出来栄えを確認出来ると書いてあった。曰く
To see how this works, let's set up a project for serving the default hello world app through pulp server. $ mkdir hello-server $ cd hello-server $ pulp init We need an index.html file to load our compiled PureScript code. Place this in your new hello-server folder: <!doctype html> <html> <body> <h1>Hello sailor!</h1> <script src="/app.js"></script> </body> </html> Now, start the server: $ pulp server It will tell you that it's launched a web server at http://localhost:1337/, and after a little while it will tell you that it's finished compiling (bundle is now VALID). If you browse to http://localhost:1337/, you should, in addition to the "Hello sailor!" header on the webpage, see that your PureScript code has printed the text "Hello sailor!" to the console.
でも、ClearLinuxには、localhostにブラウザーなんて入っていないしなあ。成果物を ブラウザーのある所へexportして確認するのも馬鹿げてる。で、数秒考えた後に、上手い 方法を思いついた。
vboxにポートフォワーディング機能が有るじゃん。それを使って localhost:1337を localhost:8080へ転送しちゃえ。そうすれば、Windows10に入ってるブラウザーは、 あたかもClearLinuxに入ってるように振る舞うぞ。
sakae@clr:~/hello-server$ pulp server * Server listening on http://localhost:1337/ * Building project in /home/sakae/hello-server * Build successful. * Bundling JavaScript... * Bundled.
こうしておいて、http://localhost:8080/ へアクセスするも、応答無しというつれない 返事がブラウザーよりありました。
こういう時は、慌てずに調査です。output/app.jsが出来上がってました。これ、nodeから 叩けるそうなので、
sakae@clr:~/hello-server$ node output/app.js Hello sailor!
出来上がったのは、どうやら動いている風です。そうすると、そのapp.jsをブラウザーが ロードするindex.htmlがちゃんと動くかな。/app.jsを取ってこいという事は、output直下が 昔の言葉でいうドキュメントルートになるはず。
index.htmlをoutputの中に持って行って実行してみるも、やはり応答無し。 となると、ポートフォワーディングが上手くいかないのかな?それとも、サーバーが たたないのかな?
代替のサーバーを、pythonで動かして確認しよう。
sakae@clr:~/hello-server/output$ python3 -m http.server 1337
こうやっておいて、Windows10側から、localhost:8080/ をアクセスすると、ちゃんと アクセス出来たぞ。これで、ポートフォワーディングはvboxがちゃんと取り計らってくれてる 事が確認出来た。
次は、pulpがちゃんとサーバーを上げてるか?
sakae@clr:~$ netstat -na Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:1337 0.0.0.0:* LISTEN
ちゃんと聞き耳をたててるようです。
curlで確認します。
sakae@clr:~$ curl http://localhost:1337/ <!doctype html> : </html> sakae@clr:~$ curl http://localhost:1337/ sakae@clr:~$ curl http://localhost:1337/ curl: (7) Failed to connect to localhost port 1337: Connection refused
最初のアクセスは、index.htmlを指示通り、プロジェクト-dirの直下に置いた場合。 二度目のアクセスは、それを消した場合。三度目のアクセスは、サーバーを落とした場合 です。
ここまでを総合すると、サーバーは、プロジェクト直下のindex.htmlを見て動いてる。 直下がドキュメントルートだとすると、output/app.jsになるはずだな。そういう設定を 行って、アクセスするも、やはりエラーがです。接続がリセットされましたですって。 もうわけわかめ。(尚、Windowsでのlocalhost指定は、ブラウザーによって挙動が違うので、 IP直指定が確実。これTipsだな。)
pulp server は、app.jsを作る事に専念させ、サーバー業務はpythonに担ってもらおう。 ちょいと情けないけどね。それとも、作者にご相談する? まてまて、折角の機会だから、ソースぐらい見ておけ。Server.purs
data BuildResult = Succeeded | Failed getBundleFileName :: Options -> AffN String getBundleFileName opts = (_ <> "/app.js") <$> getOption' "buildPath" opts
決め打ちと言うか、特に指定が無い場合のデフォルトかしら。そして、
action :: Action action = Action \args -> do let opts = Map.union args.globalOpts args.commandOpts out <- getOutputter args bundleFileName <- getBundleFileName opts hostname <- getOption' "host" opts port <- getOption' "port" opts -- This AVar should be 'full' (i.e. contain a value) if and only if the -- most recent build attempt has finished; in this case, the value inside -- tells you whether the build was successful and the bundle can be served -- to the client. rebuildV <- AVar.makeVar server <- liftEff $ createServer rebuildV bundleFileName listen server { hostname, port, backlog: Nothing } out.log $ "Server listening on http://" <> hostname <> ":" <> show port <> "/\ "
読めそうで読めない、方言が有るな。これはもう最初からやらにとだめだな。そんなあなたに お勧めのとっておきの資料は、
そして、太っ腹な事に、上記の本のテキストやcodeが、下記に公開されてます。 purescript-book
exec
早速コードを実行してみるか。基本的には、下記のようにやるようだ。
sakae@clr:~$ cd chapter3/ sakae@clr:~$ bower update sakae@clr:~$ pulp build
盛大なエラーが出て来るな。エラー潰しにtoolが欲しい。そうだ、emacsにお願いしよう。
purescript-modeと psc-ide-emacsを入れる。
M-. で、定義に飛んでいけるのがとんでもなく便利だ。
そして、対象を広げてみるか。この間入れた Debian 9 を土台にしよう。でも、基礎となるnodeは、セキュリティの関係で、下記の ようにするのが良いそうだ。nodeも足が速いけど、2019年まではサポートされるLTS版 らしい。
curl -sL https://deb.nodesource.com/setup_6.x | sudo bash - sudo apt install nodejs
deb9:~$ node -v v6.11.0 deb9:~$ npm -v 3.10.10
purescriptのコンパイラーは、バイナリー版を入れた。後は、nodeの関係だな。
npm install pulp bower
Windows版Linux
これ、雑誌の抜粋かな? 詳しい事は、雑誌でとかの宣伝臭が無いね。