技術書典にて人生初の同人誌を頒布します!

技術書典にて人生初の同人誌を頒布します!うおぉぉ!!ドコドコドコ!プワプワー!

『遠回りして学ぶ Yesod 入門(上)』

f:id:kakkun61:20160613123319p:plain:w300

内容は、入門書程度の内容の Haskell を理解した人がウェブアプリケーションフレームワーク Yesod を使うときに手助けになるような内容です。具体的には次の通り。

  • ビルドツール Stack
  • 効率のよい文字列の扱い
  • Web Application Interface とは
  • Scotty を使ったウェブアプリ

ただ書いてたら最後まで間に合わない気がしてきたので今回は「上巻」ってことで逃げました!これから下巻書かなきゃ。

ペンタブレットを買って表紙も自分で書きました!絵がうまい人ってすごい!

いろいろ初めてのことだらけで至らないところもあると思いますが会場にいらしていただければ幸いです。

  • 技術書典
  • 2016年6月25日 土曜日
  • 秋葉原通運会館
  • A-34 卓

PDF で見本誌も用意したのでぜひご覧ください。

まだ確定してませんが、紙の書籍には電子版のダウンロード権も付けようと思います。早くに売り切れたりしたら後日電子版のオンライン販売もするかも?皮算用かしら。

それでは会場で!待ってます!!

PC 環境

ディスプレー買い足そうかって思ったときに「端子空いてたっけ?そもそもグラボ何だっけ?」ってなったので書き残しておこうと思った。

CPU

Intel Core i5 4440

ark.intel.com

  • 3.1GHz
  • 4コア
  • 6MB キャッシュ

マザーボード

ASRock Fatal1ty H87 Performance

www.asrock.com

  • LGA 1150
  • PCIe
    • PCIe 3.0 x16 1つ
    • PCIe 2.0 x16 1つ
    • PCIe 2.0 x1 2つ
  • 映像出力
    • DVI-D 1つ
    • D-Sub 1つ
    • HDMI 1つ
  • 映像入力(出力へのリダイレクト)
  • Ethernet
    • 8P8C (RJ-45)
  • SATA
    • SATA3 6つ
  • USB
    • USB 3.0 6つ
    • USB 2.0 8つ(内1つ Fatal1ty マウス ポート)

メモリー

16GB

メーカー忘れた。

ストレージ

Seagate Barracuda 2TB (ST2000DM001)

http://www.seagate.com/jp/ja/internal-hard-drives/desktop-hard-drives/desktop-hdd/#specswww.seagate.com

WD GREEN 3TB (WD30EZRX-1TBP) 2つ

www.wdc.com

光学ドライブ

LG BD ライター (BH14NS48)

www.lg.com

グラフィックスボード

ASUS STRIX-GTX750TI-OC-2GD5

www.asus.com

  • NVIDIA GeForce GTX 750 Ti
  • PCI Express 3.0
  • ビデオメモリ 2GB
  • インターフェース
    • DisplayPort 1つ
    • HDMI 1つ
    • DVI-I 1つ
  • HDCP 対応
  • 消費電力最大75W
  • 2スロット分のスペース

テレビチューナー

アースソフト PT3

http://earthsoft.jp/PT3/index.htmlearthsoft.jp

電源

COUGAR GX-S 600W

http://www.milestone-net.co.jp/product/cougar/power_supply/gx-s.htmlwww.milestone-net.co.jp

筐体

Fractal Design CORE 3000

http://www.fractal-design.jp/home/products/cases/discontinued-products/core-3000www.fractal-design.jp

ディスプレー

Amark EB2126DA

www.giga-zone.com

  • Model number EB2126DA
  • 型番 TAB2126WAD-G13R
  • 21.5型
  • TN 液晶
  • インターフェース
    • D-Sub 15ピン
    • DVI-D
  • 1920×1080画素
  • 壁掛け VESA 100×100mm
  • HDCP 非対応

ディスプレーアーム

Green House GH-AMCA03

www.green-house.co.jp

  • 4軸
  • 2アーム
  • 27型 9kg まで

カードリーダー

NTT Communications SCR3310-NTTCom

www.ntt.com

Gulp でビルドスクリプトを書く(PureScript で Hello, World!)

これらに続く第4話。前回では NPM の scripts を使ってコマンドを書いてビルドをしていたんだが、sh と cmd と2つ管理しないといけなかったり、ワンライナーなんで保守がしづらかったりと問題があるので、今回はビルドツールである Gulp を使って PureScript のコードをビルドするようにする。

おさらい

前回使ったワンライナーはこんなんだった。

bower install && psc --ffi bower_components\purescript-*\src\**\*.js bower_components\purescript-*\src\**\*.purs src\Main.purs && psc-bundle output\*\*.js --module Main --main Main -o output\main.js && copy src\index.html output\

4つのステップがあるのでそれぞれ見ていく。

bower install

bower.json に記載した依存をインストールする。

psc --ffi bower_components\purescript-*\src\**\*.js bower_components\purescript-*\src\**\*.purs src\Main.purs

PureScript ソースコードコンパイルして JavaScript に。

psc-bundle output\*\*.js --module Main --main Main -o output\main.js

CommonJS 仕様の JS コードをブラウザーで実行できるように変換する。

copy src\index.html output\

JS を読み込む HTML を成果物フォルダーにコピーする。

bower install は初回にこれをそのまま実行してもらうとして、それ以外を Gulp スクリプトに変換していく。

gulpfile.js

Gulp スクリプトは単なる JS のコードで require('gulp') すると使える内部 DSL である。今のワンライナーでは psc コマンドで生成される途中成果物と psc-bundle した後の最終成果物が同じフォルダー下にあって管理の問題上分けたいので、最終成果物は dest フォルダー下に置かれるようにする。そうすると、所望の Gulp スクリプトは下記のようになる。これを gulpfile.js として保存する。

'use strict';

var gulp = require('gulp');
var purescript = require('gulp-purescript');

var sources = [
  'src/**/*.purs',
  'bower_components/purescript-*/src/**/*.purs',
];

var foreigns = [
  'src/**/*.js',
  'bower_components/purescript-*/src/**/*.js'
];

var destination = 'dest';

gulp.task('make', function () {
  return purescript.psc({ src: sources, ffi: foreigns });
});

gulp.task('bundle', ['make'], function () {
  return purescript.pscBundle({
      src: 'output/**/*.js',
      output: destination + '/main.js',
      module: 'Main',
      main: 'Main'
  });
});

gulp.task('copy', function () {
  return gulp.src(['src/**/*.html'])
             .pipe(gulp.dest(destination));
});

gulp.task('default', ['bundle', 'copy']);

雰囲気でだいたい分かると思うが簡単に説明すると、require('gulp-purescript') で Gupl スクリプト内で PureScript 固有の記述ができるようになる。gulp.task 関数は第1引数にタスク名、第2引数に依存するタスクの配列、第3引数にタスクの内容のクロージャーを渡すようになっている。第2・第3引数は省略することができる。

このようにタスクを記述すると下記のようにタスクを実行することができるようになる。

> gulp make

引数なしで gulp とだけ実行すると default タスクが実行される。

依存の追加

新たに、Gulp を使用するようになったので package.jsondevDependenciesgulpgulp-purescript を追加する。

  "devDependencies": {
    "purescript": "0.7.2",
    "bower": "^1.4.1",
    "gulp": "^3.9.0",
    "gulp-purescript": "^0.7.0"
  }

NPM でインストールした Bower と Gulp を呼べるように package.jsonscripts を下記のようにする。当然既存のワンライナーのビルドコマンドはもう要らない。

  "scripts": {
    "bower": "bower",
    "gulp": "gulp"
  }

ビルド手順

以上をまとめるとビルド手順は下記となる。

> npm install
> npm bower install
> npm gulp

ビルドを少し速くする

今の copy タスクでは前回ビルドから変更点がなくてもコピーしてしまっているので、最終変更日時を確認して必要のあるときだけコピーするようにする。変更点は下記である。

package.json

  "devDependencies": {"gulp-newer": "^0.5.1"
  }

gulpfile.js

var newer = require('gulp-newer')
…
gulp.task('copy', function () {
  return gulp.src(['src/**/*.html'])
             .pipe(newer(destination))
             .pipe(gulp.dest(destination));
});

実行するコマンドに変更はない。

NPM と Bower に依存を管理させる(PureScript で Hello, World!)

前々回の記事「PureScript ver. 0.7.0 以上での Hello, World!」、前回の記事「PureScript ver. 0.7.0 以上で “ブラウザーで” Hello, World!」に次ぐ記事。

NPM の package.json とか Bower の bower.json とかに依存を書いてビルドを簡単にするのが今回の目的。

おさらいと前提

ファイル一覧。

> dir /b
src
> dir /b src
index.html
Main.purs

ファイルの中身。src\index.html は下記。

<html><head><script type="text/javascript" src="main.js" ></script>

src\Main.purs は下記。

module Main where

import Control.Monad.Eff.Console (log)

main = log "Hello, World!"

NPM と Bower と依存するパッケージはすでにインストールしてある前提。

package.json

NPM の設定ファイルは package.jsonnpm init コマンドでいくつか質問に答えれば下記のような package.json ができるはず。

{
  "name": "purescript-hello-console",
  "version": "1.0.0",
  "main": "index.html",
  "dependencies": {},
  "devDependencies": {
    "bower": "^1.4.1",
    "purescript": "^0.7.0"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+ssh://git@github.com/kakkun61/purescript-playground.git"
  },
  "author": "Kazuki Okamoto",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/kakkun61/purescript-playground/issues"
  },
  "homepage": "https://github.com/kakkun61/purescript-playground",
  "description": ""
}

dependencies のバージョン番号のところの ^ はセマンティックバージョンを考慮して互換性のあるバージョンを表す NPM の文法らしい。

bower.json

Bower の設定ファイルは bower.json。NPM と同じように bower init コマンドで質問に答えていけば下記のような bower.json ができるはず。

{
  "name": "purescript-hello-console",
  "version": "1.0.0",
  "main": "index.html",
  "authors": [
    "Kazuki Okamoto"
  ],
  "license": "MIT",
  "homepage": "https://github.com/kakkun61/purescript-playground",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "purescript-console": "~0.1.0"
  }
}

~^ みたいなものっぽいけどいまいち分かってないので「node.js - What is the bower version syntax? - Stack Overflow」読んどいて。(丸投げ

ここまでで npm installbower install で依存をインストールすることはできるようにはなるけどビルドは手打ちなんでスクリプトにしておく。

NPM のスクリプト機能

package.jsonscripts の項目に下記を追記する。

    "build": "bower install && psc --ffi 'bower_components/purescript-*/src/**/*.js' 'bower_components/purescript-*/src/**/*.purs' src/Main.purs && psc-bundle output/*/*.js --module Main --main Main -o output/main.js && cp src/index.html output/",
    "build-cmd": "bower install && psc --ffi bower_components\\purescript-*\\src\\**\\*.js bower_components\\purescript-*\\src\\**\\*.purs src\\Main.purs && psc-bundle output\\*\\*.js --module Main --main Main -o output\\main.js && copy src\\index.html output\\",

ユーザーが NPM で Bower をインストールしたことを考えると bower コマンドにパスが通ってない可能性があるので $(npm bin)/bower ってしておくべきなんだけど、package.json の中に書く場合は npm bin がパスに追加されている。($(npm bin)/bower だけ cmd じゃない…… cmd で同じことしようとすると for /f "usebackq" %p in (`npm bin`) do %p\bower とかになるはず。)

ここまで準備するとユーザーは NPM をインストールした後、下記コマンドでビルドしできた output\index.html をブラウザーで開けばよい。

> npm install
> npm run build-cmd

編集

2015.10.18

package.jsondependencies に記述していた bowerpurescriptdevDependencies に移した。これらは成果物が依存しているわけではなく開発時にのみ依存するため。

PureScript ver. 0.7.0 以上で “ブラウザーで” Hello, World!

先日の記事では Node で Hello, World! するところまでできた。では、それをブラウザーで動かすにはどうするんだって思って調べてうまくいったのでまとめる。

CommonJS

psc コマンドで吐いた Javascript には require 関数が使われてて複数のファイルに分かれていてこいつどうするんだって思ってたんだけど、これは CommonJS っていう仕様なのね。ブラウザーは CommonJS に対応してないので(全部がそうか調べたわけじゃないけど)こいつをなくす変換をする必要がある。

Browserify

require ブラウザー」とかで検索すると Browserify (とか RequireJS)が引かっかるのでそれを使うのかと思ったんだけど、これを使わなくていいみたい。

psc-bundle

この WikiPureScript Without Node」に書いてあって psc-bundle コマンドを使えばいい。psc をインストールしたときについてきているはず。このコマンドを使うとモジュールに分かれた JS を1つにまとめた JS にしてくれる。

> psc-bundle output\*\*.js --module Main --main Main -o main.js

--module オプションと引数で、どのモジュールがエントリーポイントなのかを指定する。そのモジュールから辿れない関数は成果物から除去される。このオプションがなければ依存モジュールの全部の関数が成果物に含まれる。

--main オプションと引数で、実行される main 関数のあるモジュールを指定する。JS 読み込み時に実行したいわけではなかったらこのオプションは要らない。

-o オプションと引数でどのファイルに出力するかを指定する。なければ標準出力に出力される。

残りの引数には psc コマンドで生成された JS を指定する。

これで先日の Main.purs をコンパイルした JS をバンドルすると下記 JS が生成される。

// Generated by psc-bundle 0.7.1.0
var PS = { };
(function(exports) {
  /* global exports, console */
  "use strict";

  // module Control.Monad.Eff.Console

  exports.log = function (s) {
    return function () {
      console.log(s);
      return {};
    };
  };
 
})(PS["Control.Monad.Eff.Console"] = PS["Control.Monad.Eff.Console"] || {});
(function(exports) {
  // Generated by psc version 0.7.1.0
  "use strict";
  var $foreign = PS["Control.Monad.Eff.Console"];
  var Prelude = PS["Prelude"];
  var Control_Monad_Eff = PS["Control.Monad.Eff"];
  exports["log"] = $foreign.log;;
 
})(PS["Control.Monad.Eff.Console"] = PS["Control.Monad.Eff.Console"] || {});
(function(exports) {
  // Generated by psc version 0.7.1.0
  "use strict";
  var Control_Monad_Eff_Console = PS["Control.Monad.Eff.Console"];     
  var main = Control_Monad_Eff_Console.log("Hello, World!");
  exports["main"] = main;;
 
})(PS["Main"] = PS["Main"] || {});

PS["Main"].main();

そして下記の HTML ファイルを生成してブラウザーに読ませると無事ブラウザーのコンソールに Hello, World! が表示される。

<html><head><script type="text/javascript" src="main.js" ></script>

参考

PureScript ver. 0.7.0 以上での Hello, World!

PureScript 0.7.1.0 で Node でコンソールに Hello, World! するところまでできたのでそのまとめ。

実例による PureScript を読んで勉強していたんだけど、先月終わりのバージョンアップの関係でそのままでは動かなくって調べたんでまとめる。英語の本家の方のドキュメントもこれから対応させていくらしい。

コマンドは Windows コマンドプロンプトのを使っているので UNIX 系の人は適宜読み替えること。

環境構築

用意するものは、PureScript コンパイラー(psc)と Node(NPM も使う)と Bower。(好みによって Cabal も。)NPM と Bower (と Cabal)がどういう使い分けをされてるかは以下な感じ。

  • NPM
    • Bower のインストー
    • Grunt のインストール(自分はまだ使ってない)
    • 開発ツールの管理に使うっぽい
  • Bower
    • purescript-prelude のインストー
    • ライブラリーの管理はこっちでするっぽい
  • Cabal

psc のインストー

Homebrew なり Chocolatey なり NPM なり Cabal なり、直接バイナリーをインストールするなりする。詳しくはこちら

Cabal というか Stack が楽なので Stack でインストールする方法は次の通り。

Stack はここからバイナリーをダウンロード。stack setup して、stack install purescript すると Stackage にないファイルが必要だといわれるのでそれを設定ファイルに記述する。設定ファイルの場所は Windows なら %USERPROFILE%\AppData\Roaming\stack\global\stack.yaml。さっきのエラーにファイルの場所が書かれている。設定ファイルに追記するものもエラーに書かれているのでそれを下記のように追記する。

extra-deps:
    - aeson-better-errors-0.9.0
    - bower-json-0.7.0.0
    - boxes-0.1.4
    - pattern-arrows-0.0.2

で、もう1度 stack install purescript するとインストールされる。どこに実行ファイルが保存されたかが表示されるのでパスを通す。

Node と NPM のインストー

apt-get なり Homebrew なり Chocolatey なり直接インストーラーでインストールするなりする。

Bower のインストー

> npm install -g bower

Hello World プログラム

下記が 0.7.0 以降での Hello World プログラム。Main.purs で保存する。

module Main where

import Control.Monad.Eff.Console (log)

main = log "Hello, World!"

0.7.0 より前のは下記。

module Main where

import Debug.Trace

main = trace "Hello, World!"

0.7.0 での変更点から今回のプログラムに関係するものを取り出すと下記になる。移行ガイドもある。

  • Debug.Trace モジュールは Control.Monad.Eff.Console モジュールに置き換えられた
  • psc に標準ライブラリーがついてこなくなった

コンパイル

先のプログラムが依存するモジュールをインストールする。

> dir
Main.purs
> bower install purescript-console
> dir bower_components
purescript-console
purescript-eff
purescript-prelude

コンパイルする。

> psc --ffi 'bower_components\purescript-*\src\**\*.js' 'bower_components\purescript-*\src\**\*.purs' Main.purs
> dir output
Control.Monad.Eff
Control.Monad.Eff.Class
Control.Monad.Eff.Console
Control.Monad.Eff.Unsafe
Main
Prelude

実行

生成された output\Main\index.js ファイルを見ると main 関数をエクスポートするだけのプログラムになっているので、実行する Javascript を書く。ここでは main.js としておく。

require("Main").main();

Node で require するためのパスを指定して実行する。

> set NODE_PATH=%cd%\output
> node main.js
Hello, World!

参考