Haskell で CGI を書いてみよう。 続きを読む
「Haskell」タグアーカイブ
Haskell でオレオレ Num クラスを作るための考察
以前の記事に書いたように、 Haskell 標準の Num クラスには色々と不満がある:
結論としては「過去に遡って Num クラスの定義を変えるしかない」だったわけだが、時間干渉も因果律への反逆もできない我々としてはその選択肢は現実的ではないので、独自の Num クラス(オレオレ Num クラス)を作ることにする。この記事は、筆者がオレオレ Num クラスを作った際に考えたことをまとめたものである。
雰囲気で並列プログラミングをやってみる
Haskell での並列プログラミングをマスターしたい、とは言わないが、「全然わからない、俺たちは雰囲気で並列プログラミングをやっている」程度のことは言えるようになりたい。
今回は「データ構造の各要素を並列で評価する」ことを目指す。以下の内容は筆者がいい加減な知識で書いているので、そういうつもりでテキトーに読んでほしい。 続きを読む
Haskell (GHC) の型レベル自然数とリフレクションを試してみる
【2020年4月20日追記】GHCの型レベル自然数については、より網羅的な記事を書いた。型レベル自然数についてより詳しく知りたい方は、こちらの記事も参照いただきたい:GHCの型レベル自然数を理解する【追記終わり】
最近のGHCでは、自然数をパラメーターとするデータ型を定義できる。固定長リストの長さを型に持たせるとか、行列の大きさを型に持たせるとか、そういうことができる。あるいは、自然数 m に対して Z/mZ を表す型を作ることもできる。m を素数とすればこれは有限体となる。
実際に、型レベル自然数を使って Z/mZ に相当する型を作ってみよう。(名前は FiniteField とした) 続きを読む
Haskell で高速なプログラムを書くときに注意すること
Haskell は表現力が高いプログラミング言語だが、気をつけないと非効率的なコードが生成されてしまうことがある。では、どういうところに気をつければ高速なコードになるのか。少し調べてみた。
この記事に書くのは、あくまで原則とかそういうやつなので、コンパイラーの最適化(正格性解析、インライン化、自動ボックス化解除)によっては、自前で工夫しても意味がない、つまり、コンパイラーに任せた場合と同じ結果になるかもしれない。どういう場合に早くなるかはケースバイケースなのだ。 続きを読む
Haskell の Num クラスに対する不満
Haskell には Num という型クラスがあって、足し算とか掛け算の基本的な演算はここで定義されている。標準ライブラリで定義されているインスタンスとしては、 Int, Integer, Rational, Complex a などがある。
一言で言えば Num クラスは環っぽいものに対応するのだが、いろいろとアレな点がある。これを設計した人は、インスタンスとして整数、有理数、浮動小数点数、複素数くらいしか想定していないのではないか。 続きを読む
QRコードを生成するHaskellライブラリを試した
Cabal sandboxのメモ
Cabalを使ってHaskellのパッケージ管理をやっていると、依存関係がもつれて酷い事になる。あるプロジェクトで使うパッケージと別のプロジェクトで使うパッケージが干渉したりとかなんかそういうアレだ。こういう時はsandboxを使うと良いらしい。マニュアル
自分のプロジェクトのディレクトリで
$ cabal sandbox init
を実行すれば、新しいsandboxができる。何かパッケージを入れようと思ったら、そのディレクトリで普通に
$ cabal install ほげほげ
を実行すればそのパッケージはそのディレクトリに入る。
sandbox内のパッケージを使ってghciを起動したい場合は、
$ cabal repl
を使う。
sandbox内のパッケージを使ってghcやrunghcなどのコマンドを叩きたい場合は、1.20.0で追加された(?)execコマンドを使うといいようだ。
$ cabal exec ghc -- --make hogehoge.hs
この記事はcabal-install 1.21.0.0の時点の情報をテキトーに調べた結果を書いたので、もしかしたらもっと正しい使い方とかあるのかもしれないが、そんなもん知らん。
(9月21日: typoを修正)
さくらのレンタルサーバーにGHC+Cabalを導入した
環境
- さくらのレンタルサーバー スタンダード
- FreeBSD 9.1-RELEASE-p15 (x86_64)
- もちろんroot権限なし
- ここでは、シェルはbashを使う(デフォルトはcshだった気がする)
- ここでは、プレフィックスは
$HOME/usr
にする($HOME/usr/bin
とか$HOME/usr/lib
にファイルが入るということ)
1. GHCをインストールする
FreeBSD向けにはHaskell Platformは出ていない。しかしGHCのバイナリは配布されているので、ここからとってくる。この記事を書いている2014年7月6日の時点では、最新バージョンは7.8.2である。
$ curl -O http://www.haskell.org/ghc/dist/7.8.2/ghc-7.8.2-x86_64-portbld-freebsd.tar.xz
$ tar xf ghc-7.8.2-x86_64-portbld-freebsd.tar.xz
$ cd ghc-7.8.2
$ ./configure --prefix=$HOME/usr
この後に gmake install
をするのだが、ghc-pkgやghcが使っている共有ライブラリにパスが通っていないので、 LD_LIBRARY_PATH を設定してやる。…なんかもっといい方法があると思う。
$ echo "export LD_LIBRARY_PATH=$HOME/usr/lib/ghc-7.8.2/terminfo-0.4.0.0:$HOME/usr/lib/ghc-7.8.2/bin-package-db-0.0.0.0:$HOME/usr/lib/ghc-7.8.2/binary-0.7.1.0:$HOME/usr/lib/ghc-7.8.2/Cabal-1.18.1.3:$HOME/usr/lib/ghc-7.8.2/process-1.2.0.0:$HOME/usr/lib/ghc-7.8.2/pretty-1.1.1.1:$HOME/usr/lib/ghc-7.8.2/directory-1.2.1.0:$HOME/usr/lib/ghc-7.8.2/unix-2.7.0.1:$HOME/usr/lib/ghc-7.8.2/time-1.4.2:$HOME/usr/lib/ghc-7.8.2/old-locale-1.0.0.6:$HOME/usr/lib/ghc-7.8.2/filepath-1.3.0.2:$HOME/usr/lib/ghc-7.8.2/containers-0.5.5.1:$HOME/usr/lib/ghc-7.8.2/bytestring-0.10.4.0:$HOME/usr/lib/ghc-7.8.2/deepseq-1.3.0.2:$HOME/usr/lib/ghc-7.8.2/deepseq-1.3.0.2:$HOME/usr/lib/ghc-7.8.2/array-0.5.0.0:$HOME/usr/lib/ghc-7.8.2/base-4.7.0.0:$HOME/usr/lib/ghc-7.8.2/integer-gmp-0.5.1.0:$HOME/usr/lib/ghc-7.8.2/ghc-prim-0.3.1.0:$HOME/usr/lib/ghc-7.8.2/rts-1.0:$HOME/usr/lib/ghc-7.8.2/haskeline-0.7.1.2:$HOME/usr/lib/ghc-7.8.2/ghc-7.8.2:$HOME/usr/lib/ghc-7.8.2/transformers-0.3.0.0:$HOME/usr/lib/ghc-7.8.2/template-haskell-2.9.0.0:$HOME/usr/lib/ghc-7.8.2/hpc-0.6.0.1:$HOME/usr/lib/ghc-7.8.2/hoopl-3.10.0.1" > ~/ghc-ld-path.sh
$ source ~/ghc-ld-path.sh
$ gmake install
2. Cabalをインストールする
このへんからCabalのソースコードを落としてくる。
$ curl -O http://www.haskell.org/cabal/release/cabal-install-1.20.0.2/cabal-install-1.20.0.2.tar.gz
$ tar xf cabal-install-1.20.0.2.tar.gz
$ cd cabal-install-1.20.0.2
$ emacs bootstrap.sh
本来なら cabal-install-*
の中にある bootstrap.sh
を実行すればいいのだが、sedの仕様の違いかなんだか知らないがリンカのコマンドがおかしなことになるので、テキストエディタで bootstrap.sh
を編集してリンカを ld
に決め打ちしてやる。
LINK=/usr/bin/ld
また、そのままだと tar が /dev/sr0
だかなんだかにアクセスして死ぬので、ググって出てきた情報を元に tar
の代わりに tar -f -
を使うようにする。これは bootstrap.sh
を書き換えなくても環境変数で上書きできる。
あと、Haddockでドキュメントを生成するのがうまくいかなさそうな気配を感じたので、 --no-doc
をつけてドキュメントを生成しないようにする。
$ TAR="tar -f -" ./bootstrap.sh --no-doc
これでインストールされるはず。
環境変数 PATH
がcabalとかを見に行くように、.bash_profile
をいじってやる。
$ emacs ~/.bash_profile
export PATH=$HOME/.cabal/bin:$HOME/usr/bin:$PATH
あとは普通にcabalが使える。
$ cabal update
$ cabal install cabal-install
3. せっかくなのでCabalでいろいろインストールしてみる
なんとなくIdrisを入れてみよう!と思った。依存関係がよくわからないが、コマンドとしては
$ cabal install --upgrade-dependencies --force-reinstalls idris
ぐらいでいけるはず。…だが現実はそううまくはいかない。
遭遇した問題としては大きく分けて二つあって、テンポラリディレクトリ /var/tmp
以下で作業してるのがなぜか実行権限が与えられなくてconfigureとかでこけるのと、ソースコード中に非US-ASCII文字が入っていてこけるの。
前者は、テンポラリディレクトリを自前で用意したディレクトリに変えれば良い。つまり ~/tmp
的なディレクトリを作ってやって、環境変数 TMPDIR=~/tmp
とすればよい。
後者は、 hGetContents
が失敗する的なエラーが出る。
hGetContents: invalid argument (invalid byte sequence)
file
コマンドで問題のファイルを見るとUS-ASCIIではなくUTF-8になっているのが分かる。そこで、問題のファイルから非US-ASCII文字を探し出してやって、それをUS-ASCII文字で置き換えてやればファイルがUS-ASCIIになって hGetContents
で問題なく読み込める…という方法でビルドしたが、冷静に考えてHaskellはUnicode対応してるはずだし hGetContents
でUTF-8を読み込めないのがおかしい。終わった後に気づいたが、おそらく文字エンコーディングが設定されていない的な問題な気がするので、 LANG=en_US.UTF-8
あたりを指定すれば良かった。
結局、
$ mkdir ~/tmp
$ TMPDIR=~/tmp LANG=en_US.UTF-8 cabal install --upgrade-dependencies --force-reinstalls idris
とすれば深いこと考えずにビルドできるはず。
以前やった時はどこかで挫折してしまっていたが、今回は気合いでなんとか頑張った。普段OS X と (Arch) Linux ばかり触っていて、 FreeBSD はよくわからないのだが、まあなんとかなった。
あとはレンタルサーバーの環境にnode.jsが入れば楽しそうなのだが…。
共用サーバーに処理系をいろいろ入れていろいろやりたいというのが間違いで、そういうのがしたいならVPSでも契約しろというのは正論だろう。