再読・すごいH本 (2)

子供たちはまだ夏休み中。朝早くからラジオ体操に駆り出されるのは、今も昔も変わらぬ 光景。

昼間は何してるかと言うとオイラーの頃は、プール通いが楽しみだったな。但し地区によって 通える日が決まっていた。学童が多かったのでいつでもってしちゃうと、イモ洗いプールに なっちゃうから。

プールに行けない日は、川へ洗濯にじゃなくて、川へ魚取りにって事が多かったな。釘を3本 ぐらい使った手製のヤス(あるいは、チャリンコ屋から貰ってきた自転車のスポークに柄をつけた物)と水中眼鏡を持ってね。獲物は、その場で焼いて食べた。

今の子は、そんな遊びをさせてもらえない。川が汚いとか川は危ないとか言われて、禁止事項の 筆頭に挙げられているだろう。

で、何をやって遊んでる? この地区の流行りは、 ブレイブボード だ。子供たちは、昼間は車が居ないアパートとかの駐車場に集まって、そこですいすいと 陸上サーフィンやってる。

上手な子だと、足をくねくねしながら、多少の坂だと上ってしまう。なんか、自然に反してるぞ。オイラーは、昔、ターフスキーなんてのをやったものだ。

短いスキーの裏側にローラーを取り付けたスキーで、草原を滑り下りるやつ。爽快だったなあ。 この変形として、砂場スキーもあるそうだけど、生憎とこの地方には巨大な砂場は無い。 きっと、鳥取あたりでは流行っているんだろうな。県知事推奨夏の定番な遊びとか言ってね。

何はともあれ、暑さに負けずに頑張って遊んでください。

関数プログラミング実践入門

なんて本を、すごいH本の副読本として買ってみた。関東に住んでいれば、勉強会でその筋の 人達に会えて、どんな風に開発してるかって事も聞き出せるんだけど、ここから勉強会に 出かけるのは絶望に近い。ならば、飲み会1回分と言う事で、同本を手にした次第。

なお、情熱のある新潟の某氏は、SICPの勉強会の為だけに東京まで出てきた事を知っているぞ。 今はその情熱を持って、会社を興したと聞いているけど、順調に行っているのだろうか? なにはともあれ、頑張ってください。

関数プログラミング実践入門をちらちら見てると、stackを使ってると、だんだんとdirが肥大してくるよって書いてあった。 オイラーのclearLinxuに入れてるそれはどうよ? Webを見ててもそういう負の側面に 振れた人はだれもいない。みんな富豪なんだなあ。

sakae@clr:~$ du -sh .stack
3.3G    .stack
sakae@clr:~$ cd .stack
sakae@clr:~/.stack$ du -sh *
35M     build-plan
4.9M    build-plan-cache
4.0K    config.yaml
740K    global-project
769M    indices
1.9M    precompiled
1.4G    programs
13M     setup-exe-cache
1.2G    snapshots
20K     templates

確かに肥大してるな。このdirの中にhaskell本体を含めて一切喝采入っているから、2Gぐらい にはなっていると思ったんだけど、ここまで肥大してるとは。内容をみると、precompildって のが、どうも生活習慣によって肥大する元凶のようだ。いろいろとパッケージがコンパイル されているんだろうな。

sakae@clr:~/.stack$ stack exec ghc-pkg list
/home/sakae/.stack/programs/x86_64-linux/ghc-tinfo6-8.0.2/lib/ghc-8.0.2/package.conf.d
    Cabal-1.24.2.0
    array-0.5.1.1
    base-4.9.1.0
     :
/home/sakae/.stack/snapshots/x86_64-linux-tinfo6/lts-8.17/8.0.2/pkgdb
    ansi-terminal-0.6.3.1
    base-compat-0.9.3
    clock-0.7.2
     :
/home/sakae/.stack/global-project/.stack-work/install/x86_64-linux-tinfo6/lts-8.17/8.0.2/pkgdb
    (no packages)

どうもstackってのは、Hackageにある色々なパッケージをガシガシ使う人が難を逃れるための 免罪符のようだ。オイラーは、そこまでHaskell教に毒されていないので、そんな専門な道具を 使う事もまだ無いだろう。

ああ、肥大化というと、ClearLinuxのバンドルを受け渡す所が異常に大きくなっているな。 dirのサイズだけで優に1Mを越えている。まあ、こちらは、気が付いたら、気軽に削除して おけば済むんだけど、stackの方は、そういう訳にもいかないだろうな。

haskell on Debian

そんな訳で、深入りせずに、Haskellの浜辺でぴちゃぴちゃやってみる。新しい世界が良い だろうってんで、virtualBoxにDebianを入れてみた。

debian:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 9.1 (stretch)
Release:        9.1
Codename:       stretch

今入れると、9.1か。で、デフォでどんな関係者が居るか探ってみた。libなんとかが大量に リストされるんで、フィルターしたぞ。

debian:~$ apt-cache search haskell | egrep -v '^lib'
ghc-mod-el - Happy Haskell programming with Emacs
haskell-platform - Standard Haskell libraries and tools
hlint - Haskell source code suggestions

万人のためのプラットフォームと、emacs用のhaskell-modeを補強するやつ。それに悪い書き方を添削してくれるやつを入れた。後はお好みで、書いてる最中にちょっかいを出してくれると いう疑似ペアプログラミング用のflycheck。こいつは、elpaからどうぞ。

(add-hook 'haskell-mode-hook 'turn-on-haskell-indent)
(add-hook 'haskell-mode-hook 'font-lock-mode)
(add-hook 'haskell-mode-hook 'inf-haskell-mode)
(defadvice inferior-haskell-load-file (after change-focus-after-load)
  "Change focus to GHCi window after C-c C-l command"
  (other-window 1))
(ad-activate 'inferior-haskell-load-file)

(autoload 'ghc-init "ghc" nil t)
;(autoload 'ghc-debug "ghc" nil t)
(add-hook 'haskell-mode-hook (lambda () (ghc-init)))

;(add-hook 'after-init-hook #'global-flycheck-mode)
(setq browse-url-browser-function 'eww-browse-url)

emacsの設定はこんな感じ。ドキュメント等を閲覧するためにブラウザーが必要。定番はw3m なんだけど、今回はemacs備え付けをewwにしてみた。

Usage of Emacs front-end

ghc-modの使い方は、上記を参照。

ewwなんてブラウザーは普段使っていないものだから、ちょっと面食らった。画面を進めたり戻したりするのは、less風なキーバインドになってて、それぞれスペースとバックスペースに割り付けられている。

リンクポイントをひょいひょいとカーソル移動させるのはタブキー。直交するキーは何に なってるのだろう? まあいいや、目当ての所に来たらリターンを叩けば、リンクの先に 飛んで行く。元に戻るには、なんと l(エル)キーになってたぞ。作者はhjklキーに 思い入れが有るのだろうか?それって、vi屋が好むダイヤモンドじゃなかろうか。

ついでにghc-modで嬉しいのは、importの所で、C-M-d すると、モジュールの取り扱い説明を 参照出来る事。取り扱い説明と言いつつ、使用例がちっとも出てこないという不都合には、 取り合えず目をつぶっておこう。

調べたい関数の所で、C-c C-h すると、カーソル下の関数を引数にしてhoogleが起動して くるぞ。これも何気に親切だな。

hlintの実行例

hlintってのは、いわゆる添削君だ。どこかの学習塾で流行っているやつね。早速洗礼を受けて みる。お題は、オイラーが初めてhugsで書いた、血圧データを月毎にまとめてくれるやつ。 GHCでも、僅かな修正で動いた。

sakae@clr:~/ym/src$ hlint ym.hs
ym.hs:12:29: Suggestion: Use head
Found:
  x !! 0
Why not:
  head x

ym.hsの12行目で、headを使ったらどうでっしゃろとご宣託。元ソースは、配列のアクセスを 意図してる。インデクッス番号が0って事は、先頭って事。それならheadの方がアクセス速いと 思うんだけど、何故そうしないと言ってるんだな。お説ごもっともです。

ym.hs:19:12: Suggestion: Redundant bracket
Found:
  x !! (fromEnum k)
Why not:
  x !! fromEnum k

今度は、カッコなんて不要でっせというご宣託。関数と引数の結合度は最強でっせっていう 常識を思い出したぞ。

ym.hs:60:19: Suggestion: Move brackets to avoid $
Found:
  (head $ head cs) `div` 10000
Why not:
  head (head cs) `div` 10000

これも結合則の問題だな。これを書いた時は、divの左側をくくり出そう、そうすると、csの headを取ったもののheadって事で、lisp思考宜しく、(caar cs) を表現したかったんだな。 こうして、添削君が何を考えたか想像しながら、haskell作法に染まっていくんだな。

こんど、何か書いたら添削してみよう。

ghc-8.2.1

Haskellを使おうなんて言う案内を見ていたんだ。そしたら、 Haskell-jpへようこそ!が何時の間にか出来ていて、そこで 新種のGHCが出てるとよって案内されてた。

それから、Haskell by Exampleなんていう、 CookBookみたいなのも有る事を知った。ちょっとした実験材料を調達するにはうってつけ。

で、実験場なんだけど、OpenBSDのパッケージで提供されてるghciが動かないんだ。昔から ずっとそうだったので、何か裏技でも有るのかしら。

余り期待しないで、 GHC 8.2.1 availableの DLのページを見てみると、なんとまあOpenBSD用も有るじゃないですか。これはもう、入れてみる鹿。 INSTALLの案内によると、

./configure --prefix=<my-dir>
make install

とな。この場合のmakeは、gmakeの事ね。どうもgnumakeが世界標準と思っている連中ばかりだな。OpenBSD用のtar玉に付いている案内なんで、郷に入った案内をして欲しかったぞ。まあ、 軽微な問題なんで見逃してやるか。

$ ls GHC821/bin/
ghc                 ghci                hp2ps               runghc-8.2.1
ghc-8.2.1           ghci-8.2.1          hpc                 runhaskell
ghc-pkg             haddock             hsc2hs
ghc-pkg-8.2.1       haddock-ghc-8.2.1   runghc

これがGHCチームの皆さまからの提供品。そして、

$ ghc-pkg list
/usr/local/GHC821/lib/ghc-8.2.1/package.conf.d
    Cabal-2.0.0.2
    array-0.5.2.0
    base-4.10.0.0
    binary-0.8.5.1
    bytestring-0.10.8.2
    containers-0.5.10.2
    deepseq-1.4.3.0
    directory-1.3.0.2
    filepath-1.4.1.2
    ghc-8.2.1
    ghc-boot-8.2.1
    ghc-boot-th-8.2.1
    ghc-compact-0.1.0.0
    ghc-prim-0.5.1.0
    ghci-8.2.1
    haskeline-0.7.4.0
    hoopl-3.10.2.2
    hpc-0.6.0.3
    integer-gmp-1.0.1.0
    pretty-1.1.3.3
    process-1.6.1.0
    rts-1.0
    template-haskell-2.12.0.0
    terminfo-0.4.1.0
    time-1.8.0.2
    transformers-0.5.2.0
    unix-2.7.2.2
    xhtml-3000.2.2

cabalは入っていない。そんなのよそのチームの仕事ですって態度だな。 しょうがないので、OpenBSDのパッケージになってるcabal-install-1.22.6.0.tgzを、取り合えず入れておく。後は、cabal update しとけばいいんだな。

折角なのでhlintでもインストールしようとしたら、ことごとくパッケージのインストールで 失敗する。しょうがないので、冒頭の一部だけをコンパイルして、挙動を追ってみた。

$ cabal install ansi-terminal -v
/usr/bin/gcc -dumpversion
/usr/local/GHC821/bin/haddock --version
/usr/local/GHC821/bin/hpc version
looking for tool hsc2hs near compiler in /usr/local/GHC821/bin
found hsc2hs in /usr/local/GHC821/bin/hsc2hs
  :
on the commandline: warning:
    -this-package-key is deprecated: Use -this-unit-id instead
In-place registering ansi-terminal-0.6.3.1...
/usr/local/GHC821/bin/ghc-pkg update - --global --user '--package-db=dist/packag
e.conf.inplace'
cabal: user error ('/usr/local/GHC821/bin/ghc-pkg' exited with an error:
ansi-terminal-0.6.3.1: Warning: haddock-interfaces:
/tmp/cabal-tmp-91999/ansi-terminal-0.6.3.1/dist/doc/html/ansi-terminal/ansi-term
inal.haddock
doesn't exist or isn't a file
ansi-terminal-0.6.3.1: Warning: haddock-html:
/tmp/cabal-tmp-91999/ansi-terminal-0.6.3.1/dist/doc/html/ansi-terminal doesn't
exist or isn't a directory
ansi-terminal-0.6.3.1: installed package info from too old version of Cabal
(key field does not match id field)
)
Failed to install ansi-terminal-0.6.3.1
World file is already up to date.
cabal: user error (Error: some packages failed to install:
ansi-terminal-0.6.3.1 failed during the building phase. The exception was:
ExitFailure 1

こういうミスマッチと言うか意味不なのは、きっと古いcabalに起因してるに違いない。 そう思ったオイラーは、最新式のcabalで試してみる事にしました。

Getting The Haskell Cabalから cabal-install tool (version 1.24.0.2)のソースを落としてきてトライすると、

$ sh -x bootstrap.sh                                                            + DEFAULT_CONFIGURE_OPTS=--enable-library-profiling --enable-shared             + EXTRA_CONFIGURE_OPTS=--enable-library-profiling --enable-shared               + GHC=ghc                                                                       + GHC_PKG=ghc-pkg                                                               + ghc --numeric-version                                                         + GHC_VER=8.2.1
  :
[83 of 84] Compiling Distribution.Simple ( Distribution/Simple.hs, Distribution/Simple.o )
[84 of 84] Compiling Main             ( Setup.hs, Setup.o )
Linking Setup ...
/usr/local/lib/libgmp.so.10.0: warning: warning: vsprintf() is often misused, please use vsnprintf()
/usr/local/GHC821/lib/ghc-8.2.1/rts/libHSrts.a(RtsUtils.o): In function `showStgWord64':

rts/RtsUtils.c:220:0: error:
     warning: warning: sprintf() is often misused, please use snprintf()
/usr/local/GHC821/lib/ghc-8.2.1/rts/libHSrts.a(RtsFlags.o): In function `copyArg':

rts/RtsFlags.c:1912:0: error:
     warning: warning: strcpy() is almost always misused, please use strlcpy()
Configuring Cabal-1.24.2.0...
Setup: Encountered missing dependencies:
process >=1.1.0.1 && <1.5

Error during cabal-install bootstrap:
Configuring the Cabal package failed.

見事にエラーですよ。cabal-installにも地獄が潜んでいるんですなあ。bootって言うぐらいだ から、これぐらいは無事にインストールさせて欲しいぞ。

ご隠居さんは、気が向くままであります。次は、新しいFreeBSDで試してみますかなあ。

pipe

上記のHaskellを使おうなんてのを見てたら、 The conduit packageなんてのを さりげなく使っていた。

ストリーミングデータをパイプに流して、処理していくってやつ。オイラーもmatzさんも 大好きな あれ だ。

H本にも載ってたな。どんな使い勝手か、プチ興味が有る。

Prelude> x .| f = f x
Prelude> [1..10]
[1,2,3,4,5,6,7,8,9,10]
Prelude> [1..10] .| filter odd
[1,3,5,7,9]
Prelude> [1..10] .| filter odd .| map (^2)
[1,9,25,49,81]
Prelude> [1..10] .| filter odd .| map (^2) .| sum
165

定義は、これまた詐欺かと思える程、簡単。パターンマッチで中置基法を実現してる。本当は、unixのパイプ宜しく、 バーチカルバーだけにしたいんだけど、記号の取り合いは先願主義がモットー。ghcが、 ガード記法で使っちゃってるので、それを避けている。

式は左から右に評価される。最左の式のサンクが潰れるので、すぐ右側にある関数を適用 出来る。その結果がデータになるので、って具合に計算が進行。 旨い事を考えたものだ。