もしプログラミング言語がお昼ごはんだったら

f:id:doloopwhile:20141220233843j:plain

ソフトウェアを開発するためのプログラミング言語には様々な種類があり、 歴史あるもの新しいもの、手軽さを重視したもの厳密さを追求したもの、など様々な種類があります。

ここでは、8種類のプログラミング言語を、それぞれお昼ごはんに例えてみました。 どれもとても美味しそうですね。

アセンブラ

f:id:doloopwhile:20141220233536j:plain

ウサギ。まず血抜きの処理から始まる。

C言語

f:id:doloopwhile:20141220233541j:plain

昔はこういうのを食べていた。

Python

f:id:doloopwhile:20141220233610j:plain

色とりどりのおかずは栄養バランスがよく、持ち運びにも便利です。

Java (Version 1.5)

f:id:doloopwhile:20141220233717j:plain

栄養バランスがよく、持ち運びにも便利ですが・・・

PHP

f:id:doloopwhile:20141220233731j:plain

ハンバーガーセット。たまに食べる分には手軽で旨い。でも毎日はちょっとね。

Go

f:id:doloopwhile:20141220233737j:plain

ステーキ定食。そうそう、こういうのでいいんだよ、こういうので。

Haskell

f:id:doloopwhile:20141220233746j:plain

マナーに厳しいおフランス料理店のフルコース。味は絶品だけど、フォークの上げ下げにも一々注意され、 メインディッシュを食べる前に追い出されました。

Common Lisp

f:id:doloopwhile:20141220233754j:plain

高級食材。いや、レ・ディシプル・ド・オーギュスト・エスコフィエのあなたにとっては最高の食材かもしれませんがね、 我々には調理する腕も時間も無いんです。今日のランチを食べたいだけなんです。

あとがき

ついカっとなってやりました。他言語の画像も募集中。

AngularJSのチュートリアルを移植して感じた、Elmの3つの良い点と不満点

これはElm Advent Calendar 2014の14日目の記事です。

AngularJSのチュートリアルをElmで再実装してみました!

doloopwhile/elm-phonecat · GitHub

まだ、本体のソースコードだけで、解説は何もないのですが・・・。

書いていて、気づいた事を、良い点・不満点それぞれ3つずつ書いていきます。

良い点1:必要な機能が十分に実装されている

Elm v0.14ではJson.Decoderが追加され、JSONのパースを実用的な記述量で実装できるようになりました。

私にとってはこれがAngularJSのチュートリアルをElmで再実装する上での「最後のピース」でした。

もちろん「ウチの業務アプリをElmで再実装してよ」と言われると「いやAngularJSの方が・・・」となります。まだElmには荒削りなところもあります。

しかし、「オモチャ」と言われる段階は脱したという印象です。

良い点2:直感的

Elmは「やりたいこと」と「解決法」がすぐ近くにある感じです。AngularJSのように新しいモジュールを勉強する回り道をしなくても、すぐに解決出来るのです。

例えば、AngularJS版のチュートリアルでは「True/Falseの代わりに"✓✗"を表示する」のために、Step-9を丸々ngFilterの説明に使っています。

一方Elmでは、

checkmark x = if x then plainText "\x2713" else plainText "\x2718"

の一行だけで用が足ります。

良い点3:エラー処理をサボれない

MaybeResultを使って、エラー処理を厳格に行えます。

JavaScriptだとNULLチェックなどは「if != null、if != null はぁ〜面倒くさいなあ」となってしまいがちですが、ElmではMaybeのチェックをしないとそもそもコンパイルが通らないので、ものぐさな私でも安全なコードを強制的に書くことになります。

まぁ、「厳格」はデメリットでもあります(JSONのフィールドを全列挙しないとDecoderが作れないとか)。

不満点1:Signalが不便(特に、ページの階層構造を作りづらい)

一方、ElmはまだSignalが使いづらいと感じました。

今回作ったのはシングルページアプリケーション(SPA)でしたが、AngularJSの場合は、

  • 実際にページを描画するTemplate/Controller
  • URLからTemplate/Controllerを選択するngRoute

という仕組みになっています。ngRoute側ではページの描画の仕方を知る必要はありません。 また、各ページのTemplate同士(例えば、トップページのTemplateと、詳細ページのTemplate)は互いの事を知る必要がありません。「関心の分離」ができる、ナイスな仕組みです。

しかし、残念ながら、現在のElmではngRouteの真似はできないようです。

-- 注:このコードは実際のElmではありません。

-- URLのハッシュによって、ページを切り替える関数
route : Location -> Signal Element
route location = 
  if | startsWith("#/phones", location.hash) -> phoneView location
     | otherwise -> indexView

-- トップページを描画
indexView : Signal Element
indexView =
  indexPageImpl <~ Time.fps 30 ~ Mouse.clicks

-- カタログの個別ページの描画
phoneView : Location -> Signal Element
phoneView location =
  let
    api = Http.sendGet ("/api/phones/" ++ String.dropLeft(8, location.hash))
  in
    phonePageImpl <~ Time.fps 30 ~ Mouse.position ~ api

-- さて、main関数の型は?
main = route <~ location

main関数はElement型かSignal Element型でなくてはならないからです。そのためmain関数は「全ページの描画とルーティングに必要な全部のSignalを<~ ~で連結する」ことになりがちです。

不満点2:union typeの処理が煩雑

ElmにはMaybeResultHttp.Responseなどのunion typeがあるおかげで、エラー処理を安全に行えるのですが・・・case文がネストしまくって大変です。

今回のチュートリアルでは、JSON APIのレスポンスを、

phonesResp : Http.Response (Result String (List Phone))

という型にしました。

実際にその値を処理している部分はこちら

case phonesResp of
  Http.Waiting ->
    Text.plainText "waiting"
  Http.Failure code text ->
    Text.plainText ("failed with " ++ (toString code) ++ " " ++ text)
  Http.Success resultPhones ->
    case resultPhones of
      Err error ->
        Text.plainText error
      Ok phones ->
        indexElements q sortPhones phones

JavaScriptだったら「早期リターンに書きなおすこと -1 f:id:doloopwhile:20141215023108p:plain」と、コードレビューで却下されても仕方ない感じのコードをElmでは書かざるをえません。

また、標準ライブラリのSignal Maybeモジュールも、「Signal (Maybe a)からNothingではない値を取り出して返すSignal a」のような関数が無いなど、細かい関数も不足しています。

悪い所3:レイアウト・スタイルライブラリの不足

ElmはHTML/CSSよりずっと直感的にレイアウト・スタイルを書けるのですが、やはりまだ機能不足です。

例えば、

  • CSSの"border"相当のものが無い(containerを2つ重ねて無理やりborderを表現することはできます)。
  • plainTextcontainerで囲んでも、中の文字列は改行されない(自動で改行させる方法がない?自分で改行位置で分割してText.Lineなどを使えば可能)。
  • 「画像を400x400に収まるように縦横比率を変えずにリサイズ」などができない(そもそも画像サイズを取得できない。Portを使えば無理やりできなくもないかもしれないが・・・)

一般的に、基本的なことはElmの方がAngularJSより簡単に出来るのですが、上に上げたような事を実装しようとするとElmでは不可能ではないものの多くの労力を割いて、細かいところまで実装しなくてはなりません。

「よくある処理」「80%のケースを20%の労力でカバーできるデフォルトの選択肢」がもっと用意されればいいな、と思いました。

f:id:doloopwhile:20141215024400j:plain

あとがき

Elm Advent Calendar 2014にはまだ十分な余裕がございます。ふるってご参加ください。

Elm 0.14に際して思ったこと

Elm 0.14がリリースされました。

今回のリリースには後方互換性が保たれない、大きな変更が含まれてます。 これによりHaskellとの違いが大きくなったため、もはや「Haskellベースの言語」という表現はふさわしくないかも知れません。

ところで、このような大きな変更は、メジャーな言語では、Rubyが2007年に1.9.0で、Pythonが2008年に3.0で行っていますが、その評価は対照的です。 Rubyでは1.9.0のことはもはや話題にもなりませんが、 Pythonでは未だに「2.xと3.xのどちらを使って開発すべきか」「2.x系の開発を続行するべきか」のような記事が書かれます。

私はこんな記事こんな記事を書くほどPython好きだったので、Pythonが移行の失敗例のように語られるのは悲しいです。

両者の明暗が別れた理由としてよく言われるのは、

  • Rubyは本格的な普及の前に大きな変更をした。Pythonは2008年当時すでに主要なLinux内部やGoogle App Engineで使われ、かなり普及していた。
  • RubyはいわゆるWEB系で使われていたためライフサイクルが短かった。PythonはWEB系以外でも使われており、簡単に移行できなかった。*1

などがありますが、個人的には、

  • RubyではRuby on Railsを使うユーザーが多く、Ruby on Railsが旧バージョンを切り捨てれば、ユーザーも新バージョンに映らざるをえない
  • Rubyの方が元々アグレッシブで非互換性バッチコイなのユーザーが多い?(多かった?)。

のような理由もあると思います。

いずれにせよ、Elmは普及にはまだほど遠い段階なので(そもそも1.0以前ですし)、0.14での変更はElmの進化に良い影響を与えることと思います。

*1:私自身、仕事では未だに時々RHEL5.x向け製品のメンテナンスをしてますし。RHEL5.xのPythonは2.4系です。

Elmはそもそも誰が作ってるの?【Elmアドベントカレンダー2014 7日目】

これはElm Advent Calendar 2014の7日目です。 社内勉強会でElmを紹介したら、

ボス「Who is creating Elm language ?」
私 「えっ?」
ボス「Elmって誰が作ってるの?」

というわけで調べてみました。

メイン開発者はPreziの中の人

Elmコンパイラに一番多くコミットしているのはEvan CzaplickiさんWikipediaによると、もともとElmはCzaplickiさんが2012年に論文(大学の卒業論文か何か?)のために始めたプロジェクトだったそうです。

CzaplickiさんはPrezi2013年に入社しフルタイムでElmの仕事をしているそうです。elm-compilerにはCzaplickiさん以外にもPrezi社員が多いようです。

Preziはプレゼン作成用WEBサービスの会社

Prezi - YouTube

マインドマップベースのプレゼンがとってもオサレです。上手くハマればスゴいプレゼンができそうですね!

パワポやGoogleDrive等のスライド式プレゼンに慣れた身からは「使いこなせるかな?」とちょっと不安にもなりますが。

しかし、今の所、PreziのWEBツール自体は主にFlushで作られているようです。

結論

次の勉強会では、Elmの紹介プレゼンをPreziを使って作るのがいいかもしれません。

あとがき

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

Elmで青春のフラクタルを描画する【Elmアドベントカレンダー2014 6日目】

これはElm Advent Calendar 2014の6日目です。

Elmの優れた点と言えば、

  1. Haskellベースの静的型関数型言語
  2. Functional Reactive Programming
  3. 強力なレイアウト機能

などがまず挙がるでしょう。しかし、

  1. 図形描画ライブラリ

も、実はElmの長所の一つなのです。

Elmの図形描画機能

まずは 公式サイトの例をご覧ください。

HTML5Canvasは、JavaScriptによる手続き型の実装を前提にしていたので、コマ毎にclearRectで消去したり、save/restoreで状態を管理したりする必要がありました。プログラマーはともかく、「学校で習った図形を書いてみよう」と言う場合にはやや非直感的です。

一方Elmでは更新処理自体はElmがやってくれます。 また、図形はFormという「図形そのもの」を表す型として、 図形の移動や拡大縮小はmove scaleといった関数として、自然に表現できます。

なお、注意点とがあり、collage w h forms でw×hのキャンバスを作ったとき、原点はキャンバスの中心で、Xが大きくなるほど右、Yが大きくなるほど上の座標です。つまり、数学と同じ座標なのです。

フラクタルを書いてみる

図形が描ける、ならば初めにフラクタルを描くものと相場は決まっています。再帰呼出し&縮小+移動で、シェルピンスキーのギャスケットを描画してみました!

Sierpinski gasket with Elm

n = 0では単なる三角形を、n > 0では自分自身の縮小コピー×3を描画しています。

なお、Elmでは小さすぎる図形(1ピクセル未満?)は描画してくれないらしく、上の例で再帰が深すぎると何も表示されなくなりました。

自分語り&妄想:Elmは未来の十進BASIC

フラクタルを書いていると、十年前私がまだ紅顔の少年だった頃を思い出します。

私がプログラマーになったのは図書館から↓の本を借りたのがきっかけでした。

当時は悪名高いMicrosoft Visual Basicがボロクソに言われつつも全盛の時代でしたが、十進BASICVBとは全く別の"Full Basic"という規格に沿った教育用BASIC環境でした。

教育用だけあって

と、初心者用の機能が充実しているだけではなく、

  • 数値は10進小数がデフォルト(2進数モードもある)
  • 10進1000桁モード(数値型が小数点以下1000桁まで格納可能になる)
  • 有理数モード
  • 複素数モード
  • 強力な図形描画機能
    • function文とは別に、図形を定義するpicture文がある
    • scale, rotate, shift, 任意のアフィン変換, それらの合成変換
  • グラフ描画用関数
  • 図形関連の豊富なExample(含シェルピンスキーのギャスケット)

等など、数学用の機能がとても充実していました。

言うまでもなく、構造化プログラミングにも対応しており、良いプログラミングを教われなくなったり完膚なきまでに壊れることもありませんでした。

さすがに今では、プログラマー志望の高校生にはPythonあたりを薦めます。 でも、数学者・科学者志望だけどプログラミングの素養を身につけたい高校生ならば、今でも10進BASICを薦めたいと思います。(高校生の知り合いはいないけど)。

一方Elmですが、Playground、デバッガ、図形ライブラリなどは既にかなりの充実度です。 このまま発展すれば21世紀版・十進BASIC的な地位に着けるのではないか? と、ガスケットを書いていて思いました。

あとがき

おかげさまでElm Advent Calendar 2014は今のところ途切れず続いていますが、まだまだ空きがあります。ふるってご参加ください。

フラクタルで描く 魅惑的な画像の世界

フラクタルで描く 魅惑的な画像の世界

ElmとHaskellの6つの非互換性【Elmアドベントカレンダー2014 3日目】

これはElm Advent Calendar 2014の3日目です。

f:id:doloopwhile:20141204015840p:plain

ElmはHaskellベースの言語なので、Haskellの記事や入門書もElmの学習に使えます。しかし、実はElmにはチョコチョコHaskellと違うところがあって互換性はありません。

相違点をElm公式サイトLearnSyntaxFAQから抜粋して解説します。

1. Elmは遅延評価ではありません

Haskellは遅延評価なのでリスト処理の効率が良いのがウリでした。 JavaScriptにもジェネレータという形で遅延評価の思想が取り入れられています。

しかし、Elmのリストや辞書等などは遅延評価ではありません。

Elmはクライアントサイドの言語なので、遅延評価があまり役立たないこと、 SignalJavaScriptのジェネレータのような機能を持っているためのようです。

2. Elmにモナドはありません

Signalがあるので、IOモナドは不要です。それどころかMaybeモナドもListモナドもありません。したがって、do文もありません。

なお、Maybeは標準ライブラリにMaybeパッケージがあり、JavaScriptnullを使うようなコードを安全に書けます。

でも、やっぱりdo文はあった方がいいと私は思うことがあります・・・。caseを5段階ぐらいネストしたりすると。

まぁ「モナド圏論に基づいています*1」という説明が「Haskellってモナドが難しいんでしょ?」という誤解を生むことがないからいいのかな?

3. 関数関連の演算子が違う

Elm Haskell 意味 同値なJavaScript
f x <| g y z f x $ g y z (f x (g y z)) f(x, g(y, z))
g y z |> f x なし
(f << g) x (f . g) x (f (g x)) f(g(x))
(g >> f) x なし

$.がそれぞれ<|<<に変わっています。そして引数の順番を逆にした>|>>が加わっています。

4. :::の意味が逆

Elm Haskell
norm : Float -> Float -> Float
norm x y = sqrt (x * x + y * y)
norm :: Float -> Float -> Float
norm x y = sqrt (x * x + y * y)
1 :: 2 :: alist == [1, 2] ++ alist
1 : 2 : alist == [1, 2] ++ alist

これは型アノテーションの方がリストへの追加よりも頻繁に使うからです。

5. foldl系関数の引数の順序が逆

List.foldr, List.foldl はリストの要素に次々に関数を適用する関数です。 データ構造毎にDict.foldlSet.foldlといった変種もあります。他言語ではreduceinjectという名前で提供されていることがあります。

// elm
v = List.foldr (+) 0 [1,2,3]

// 同等なJS
var list = [1, 2, 3];
var v = 0;
for (var i = 0; i < list.length; i++) {
  v = v + list[i];
}

微妙な違いですがElmではList.foldlが受け取る関数の引数の順序をあえてHaskellと逆にしてあります。

Elm Haskell
List.foldl : (a -> b -> b) -> b -> [a] -> b List.foldl : (b -> a -> b) -> b -> [a] -> b
List.foldr : (a -> b -> b) -> b -> [a] -> b List.foldr : (a -> b -> b) -> b -> [a] -> b

これは、Elmでは標準ライブラリを「データ構造はいつも最後の引数」というルールで設計しているのに関係しています。

たしかに、HaskellのようにList.foldl : (b -> a -> b) -> b -> [a] -> bであったとすると、foldrにはそのまま使えるのにfoldlには使えない関数が出てきて困る気がしますが・・・私にはよく分かりませんでした。

公式サイトのLibrary Design Guidelinesにその点が書いてあるのですが、例がおかしい(間違っている?古い?)気がします。

6. 他にも色々なものがありません。

  • do文以外のモナド関連の構文や演算子
  • where文。代わりにletを使う
  • (+1) のような記法。代わりに((+) 1)と書く
  • ライブラリ

こんなに違って大丈夫?

Haskellは元もと演算子が多い(多すぎる?)言語なので、ElmではSignalが入って互換性がなくなるなら演算子も整理したいと言うことなのでしょう。

ただ「HaskellのライブラリがElmに流用できない」という懸念をもつ方もいらっしゃると思います。私も不安です。

しかし、Haskellは主にサーバーサイドやコンパイラなどに使われ、Elmはクライアントサイドのための言語なので、「ブラウザ上で動くコンパイラを作りたい」というのでもなければ、HaskellのライブラリをElmに流用する機会は実は無いのかもしれません。

あとがき

更新が24時を過ぎてしまいました。

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

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

*1:確かにモナドは圏論にルーツがありますが、 「『変数』はデカルトにルーツがあります」「正規表現はオートマトン理論に基づいています」「while文を使用することで原始計算可能な関数だけでなく真に計算可能な関数を作成することが可能になります」ってあえて説明したりしないでしょう?「モナドは圏論(ry」が使われる背景には、数学という虎の威を借りてHaskellを高尚に見せようとする心理があるように私には思えます。

ソースに一行追加するだけで実行時にバイナリをバルスできるモジュールを書いた

バズーカが弾切れ、絶対絶命のピンチ、メガネの小悪党がmain関数を実行する前に実行ファイルを削除したいというのはよくあることです。

使用例

たとえばこういうコードに・・・

// get.go
package main

func main() {
   println("ハハハハハ!飛行石を手に入れたぞー!!")
}

importをくわえるだけで・・・

// get.go
package main

import (
  _ "github.com/doloopwhile/go-balse"
)

func main() {
   println("ハハハハハ!飛行石を手に入れたぞー!!")
}

たったこれだけでバルスします!

$ go build get.go
$ ./get
panic: _人人人人人_
      > バルス!<
        ̄Y^Y^ Y^Y^ ̄

goroutine 16 [running]:
runtime.panic(0x44cc20, 0xc208000120)
    /usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
github.com/doloopwhile/go-balse.init·1()
    /home/kenjiomoto/gocode/src/github.com/doloopwhile/go-balse/balse.go:9 +0x87
github.com/doloopwhile/go-balse.init()
    /home/kenjiomoto/gocode/src/github.com/doloopwhile/go-balse/balse.go:10 +0x4b
main.init()
    /home/kenjiomoto/Downloads/get.go:10 +0x46

goroutine 17 [runnable]:
runtime.MHeap_Scavenger()
    /usr/local/go/src/pkg/runtime/mheap.c:507
runtime.goexit()
    /usr/local/go/src/pkg/runtime/proc.c:1445

goroutine 18 [runnable]:
bgsweep()
    /usr/local/go/src/pkg/runtime/mgc0.c:1976
runtime.goexit()
    /usr/local/go/src/pkg/runtime/proc.c:1445

goroutine 19 [runnable]:
runfinq()
    /usr/local/go/src/pkg/runtime/mgc0.c:2606
runtime.goexit()
    /usr/local/go/src/pkg/runtime/proc.c:1445

$ ./get
bash: ./get: そのようなファイルやディレクトリはありません

doloopwhile/go-balse

あとがき

最初は「importするだけでカレントディレクトリのファイルを全て削除」という仕様にしたところ、うっかり「README.mdがー!!README.mdがー!!」となってしまったので、実行ファイルを削除するだけのオトナシイ仕様にしました。

「ソースに一行追加するだけで・・・」は本来もっと真面目な目的で利用できるものです。