再読・すごい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にしてみた。
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が、 ガード記法で使っちゃってるので、それを避けている。
式は左から右に評価される。最左の式のサンクが潰れるので、すぐ右側にある関数を適用 出来る。その結果がデータになるので、って具合に計算が進行。 旨い事を考えたものだ。