ElmのインストールとHelloWorldのコンパイル【Elmアドベントカレンダー2014 2日目】

ElmはPlaygroundで簡単にコードを試せますが、最終的にはelmコマンドでコンパイルする必要があります。

0. バイナリをインストール

MacとWindowは、公式サイトのInstallから、 バイナリをダウンロードできます。

しかし、LinuxではHaskell Platformを使ってソースからインストールしなければなりません。

1. Haskell Platformのインストール

Haskell Platformapt-getなどでインストールできますが、古い場合があるので新しくインストールした方が良いかもしれません.

cd /
curl -L https://www.haskell.org/platform/download/2014.2.0.0/haskell-platform-2014.2.0.0-unknown-linux-x86_64.tar.gz | sudo tar xvzf -
sudo /usr/local/haskell/ghc-7.8.3-x86_64/bin/activate-hs

2. cabalのアップデートとElmのインストール

cabal update
cabal install cabal-install
cabal install -j Elm-0.13 elm-repl-0.3 elm-reactor-0.1 elm-get-0.1.3

echo 'export PATH=$PATH:~/.cabal/bin' >> ~/.bashrc

3. Hello Worldコンパイル

cd 【適当なディレクトリ】
echo 'main = plainText "hello"' > hello.elm
elm hello.elm
firefox build/hello.html

Elmとはどんな言語か?その7つの特徴【Elmアドベントカレンダー2014 1日目】

f:id:doloopwhile:20141129182134p:plain

Elmはクライアントサイド向けの関数型言語です。一体どんな言語なのでしょうか?

1. HTML/CSS/JSにコンパイルされる

ElmはHTML/CSS/JSにコンパイルして使用します。 この辺はJavaScriptコンパイルされるAltJSに似ています。 AltJS同様、Elmも特別なランタイムライブラリは不要です。

ただし、Elmは1つのソースでHTML/CSS/JSをすべてまかなえるのが特徴です。

2. 独自の抽象化レイヤーを提供している

代表的なAltJSであるCoffeeScriptは"It's just JavaScript"をモットーにしています。すなわち、文法を改良するのみで、「中身」はJavaScript以上でも以下でもありません。

一方、Elmでは直接JSやCSSを操作することはできません。 基本的にすべてElmの関数・レイアウトライブラリを使わなければなりません。

これはとっつきにくいのですが、逆に見れば「歴史的なしがらみによる汚さ」を扱う必要が無いと言うことです。

ただし、Portsを通じてJavaScriptとやりとりしたり、Canvas風にHTMLに埋め込んで使うこともできます。

3. Haskellベースである

ElmはHaskellを元に若干の修正を加えた独自言語です。

当然Elmは強力な静的型を備えています。 「0に.nameというプロパティはありません」的なエラーとは無縁です。

またあらゆるものは関数ですArray.some Array.every どころか、foldl, map, etc.. 使い放題です。

4. FRP(Functional Reactive Programing)に対応している

ElmはHaskellベースなので状態や変数はありません。

もちろん、クライアントには状態変化がありまくりです。 マウスの動き、ウィンドウサイズの変更、APIからのレスポンス etc...

JavaScriptの場合は状態変化はonmousemoveなどのcallbackを使って関数で明示的に扱うことになります。しかし、callbackが増えてきて、しかもネストしだすと何がなんだかわからなくなります。callback地獄です。

一方Elmでは組み込みの<~~を使います。

main =
  renderScene
  <~imageAPIResp
  ~ Mouse.position
  ~ Window.width
  ~ pagingAPIResp
  ~ (fps 30)

更新の処理はElmが勝手に行ってくれます。

FRPについてはこちらのスライドが大変優れているので、こちらをご覧ください。

http://www.slideshare.net/maedaunderscore/elmfunctional-reactive-programming

5. Playgroundが充実している

ElmはPlaygroundに力を入れています。

f:id:doloopwhile:20141129200243p:plain

GoなどにもPlaygroundはありますが、Elmのは、

と、かなり機能が充実しています。

また、Exampleも基本文法から、応用までそろっています。

Examples

ElmのPlaygroundのゆるかわほっこり感は、Haskellの取っ付きにくさを打ち消してあまりあるものがありますね。

6. Haskellだけど怖くない

私はHaskellはこんなイメージです。 f:id:doloopwhile:20141129201705j:plain

確かに、JavaScriptとはシンタックスが全然違うのでとっつきにくくはあります。 最初はコンパイルが通らなくて苦労します。

しかし、ElmはPlaygroundで簡単にトライ&エラーを繰り返す事ができます。 また、「最初の100個の素数を求める」のような人工的な例ではなく、目に見えて実際に動くアプリを作る事ができるので、Haskellよりモチベーションを保ちやすいでしょう。

また、ElmにはFRPがある代わりにElmにモナドはありません。

7. ElmはAnglarJSを置き換える言語である?

既にクライアントサイドには様々なAltJSやライブラリがあるのに、なぜ新しくElmを学ぶのか?

私の場合はAngularJSへの疑問でした。

AngularJSは優れたライブラリで、実際に仕事で使ってもいるんですが、 難しすぎる!

  • 3つの異なる言語(HTML/CSS/JavaScript)を同時に扱わなくてはならない。*1難しい!
  • 特定の使われ方(CRUD)に特化していて、汎用性が欠けているように見える→難しい!
  • ngBind, ngResource, ngDirective etc… 多い!→難しい!

WEBは10年20年先も存在し続けると思いますが、AngularJSが10年使われるか疑問です。

一方、Elmはシンプルです。

  • 言語は1つだけ*2
  • FRPの仕組みは汎用的(フォーム入力にも、APIコールにも、アニメーションにも何にでも使える)
  • 「すべてが関数」関数は容易に組み合わせられる

ひょっとしたら、Elmにはクライアントサイドの未来の主流になるかもしれません。 少なくともElmにヒントがあるのは確かです。

関連リンク

POSTDにElm関連の翻訳記事があります。

まず、これらをよんでモチベーションを高めてから始めるといいと思います。

あとがき

明日2日目は「Elmをインストールする」です。

Elm Advent Calendar 2014にはまだ空きがあります。ふるってご参加ください。

*1:場合によってはCoffeeScript、Less、Slimなども学ばなければなりません。

*2:基本的には。HTMLやJavaScriptと連携すれば別です。

~/.bashrcは何も出力してはいけない(するならエラー出力に)

知ってて当たり前の超凡ミス。

起こったこと:rsyncが失敗する

rsyncが何故か失敗してしまう。"protocol incompatibility"と出ていますが、--protocolオプションを指定しても、最新版のrsyncをインストールしても、同じエラーが出ます。なぜでしょう?

Tue Nov  4 12:15:46 2014 Normal: recursive startup rsync: /home/xxxxxxx/Documents/src/xxxxxxx/ -> vagrant@deva:xxxxxxx/ excluding
/cucumber/vendor
/cucumber/.bundle
~/.bashrc loaded
protocol version mismatch -- is your shell clean?
(see the rsync man page for an explanation)
rsync error: protocol incompatibility (code 2) at compat.c(174) [sender=3.1.0]
Tue Nov  4 12:15:47 2014 Error: Failure on startup of "/xxxxxxxxx".

原因:~/.bashrcでechoしている

上のログに "~/.bashrc loaded" という行があります。これが原因です。.bashrc*1の最後の行で"echo"していました。もちろん、echo以外でも、何かしらの出力をしてしまうとscpやrsyncはコケます。

# ~/.bashrcの最後の行
echo "~/.bashrc loaded"

これと同じ問題です。

bash - SCP doesn't work when echo in .bashrc? - Stack Overflow

How the SCP protocol works (Jan Pechanec's weblog)によると、 scpは初めにリモート側にプロトコルを問い合わせるのですが、~/.bashrcが何かを出力するとそれが混乱してしまうようです。多分rsyncも同様なのでしょう。

回避策:Greetingは標準エラー出力に出す

echo "~/.bashrc loaded" >&2

*1:安直に、どのOSにもデフォルトで入っているBashを使っています。本物のプログラマならバギーで文法が汚く補完が中途半端なbashではなく、堅牢で高速なdashですよね?分かっています

Goplay: Goで手軽に書捨て環境を作るツール

goreの説明を追記。

f:id:doloopwhile:20040712133434j:plain

LLから、Goに移るときの不満の一つに「標準のREPL(インタラクティブシェル)が無い」があります。

「ポインタはmapのキーになるんだっけ?」のような、つまらない(けど、ありがちな)疑問を解消するには、ドキュメントを漁るより、コードを書いてしまう方が、手っ取り早いですよね?

goplayを作った!

goplayは、書捨てGoコードを書くためのシンプルなツールです。

https://camo.githubusercontent.com/db725471459165d7d24b6e6f234b02267b187746/68747470733a2f2f7261772e6769746875622e636f6d2f646f6c6f6f707768696c652f676f706c61792f6d61737465722f64656d6f2e676966

やっているのは、 1. 一時ディレクトリを/tmp/goplay/以下に作る 2. main.goを一時ディレクトリに作る 3. 一時ディレクトリで新しいシェルを起動 4. 環境変数GOPATHに一時ディレクトリを追加。 これだけです。

インストールはgo getするだけです。

go get github.com/doloopwhile/goplay

他の方法との比較

ちゃんとしたREPL(gore)を使う

いや、正直、普通はgoreのほうがいいと思います。良い子はgoreを使いましょう。

エディタで書捨てコードを書きたい子はgoplayを使いましょう。

github.com

Go Playground

Go Playgroundはブラウザ上でGoを書いて実行できます。 しかし、

  • 外部ライブラリをimportできない
  • 好きなエディタが使えない という欠点があります。

goplayは、ローカルで実行するので、外部ライブラリもエディタも自由に使えます。

その場でvi a.goする

まぁ、それでも動くは動くんですが、

package main*.goファイルが同一ディレクトリに複数あると、 エディタのシンタックスチェッカーが、

「main redeclared in this block」

を出してくるのが五月蝿い。

そして、作ったスクリプトを削除するのも面倒くさい。

Let's go!

Go-GTKでCUIとGUIをつなぐ的なアプリを書いてみた

プログラマーは往々にしてCUI世界の住人なのですが、

ごくたまに、ファイルをドラッグ&ドロップで指定できると便利、ということがあります。

doloopwhile/dap · GitHub

スクリーンショット

f:id:doloopwhile:20141005180042p:plain

インストール

go get github.com/doloopwhile/dap

使い方

ドラッグアンドドロップでファイルをバックアップ・ディレクトリにコピーする

mkdir -p $HOME/backup
dap | xargs cp {} $HOME/backup

なぜ作ったか

Debian系OSには(dragbox)https://packages.debian.org/ja/sid/dragboxというツールがあるようです。しかし、どういうわけか私のXubuntuでは動きませんでした。

そこで、(Go-GTKのD&Dの例)https://github.com/mattn/go-gtk/blob/master/example/dnd/dnd.goを元に作ってみました。Go-GTKは、デモが充実しており、実用的に使えそうな段階に入っているようです。

Goライブラリを作ったら、とりあえずgodocdown

小さなGoライブラリをつくった時、ほとんど自分しか使わないような規模なら、わざわざREADMEに「Usage」「Example」「Functions」なんて書くのは面倒ですよね。

そんな時は、godocdownで自動生成してしまうのがオススメです。 godocと同等の内容をGitHub用Markdownで生成してくれます。

例:doloopwhile/go-merror · GitHub

go get github.com/robertkrimen/godocdown/godocdown
godocdown > README.md

まぁ、わざわざgodocdownでREADMEを作らなくても、 ほっておいてもgodocは、自動で生成されるのですが、READMEを空っぽにしておくのも寂しいので。

地味に待ち遠しいDockerの新機能

DockerfileのENV コマンドで、複数環境変数を一度に指定できるようになるらしい。 Allow ENV to set multiple variables in one layer · Issue #2333 · docker/docker · GitHub

従来は複数環境変数を設定するには、ENVを繰り返さなければなりませんでした。

ENV GOPATH /root/go
ENV CGO_CFLAGS-I/opt/fzero/include
ENV CGO_LDFLAGS -L/opt/fzero/lib64 -Wl,-rpath=/opt/fzero/lib64

この場合、各ENVごとにレイヤーが生成されてしまい、docker pushの際に通信回数が増えるなど無駄でした。

それが1行で書ける=1レイヤーで済むようになるらしいです。 イメージ:

ENV GOPATH=/root/go CGO_CFLAGS=-I/opt/fzero/include CGO_LDFLAGS="-L/opt/fzero/lib64 -Wl,-rpath=/opt/fzero/lib64"