Haskell再入門
誰だか存じ上げませんでした。
すごく分かりやすいです。
こういう風に順を追ってちゃんと説明できる人好きだな。
あ、ちなみに今のリンク先はあんま関係ないです。 過去のYコンビネータの説明やらなんやらです。cut-sea:2010/04/07 14:03:58 JST
typeclassopediaを読んでて、そういや(<*>)をSとして使ってた自分。 朝食摂取しながらサンドウィッチの包みで検証したのでメモっておく。
Applicative fのfが型(->)aの時
(<*>)::f (b->c)->f b->f c
→(((->) a) (b->c))->(((->) a) b)->(((->) a) c) →(a->(b->c))->(a->b)->(a->c) →(a->b->c)->(a->b)->(a->c)pure::b->f b
::b->(((->) a) b) ::b->(a->b) ::b->a->bつまり、(<*>)がSでpureがK! Applicative ((->)a)はSKコンビネータをプリミティブオペレータとする合成戦略を実現している。
あと
fmap g x = pure g <*> x
は
pure g <*> x = (<*>) (pure g) x
= S (K g) x = (S (K g)) x = (B S K g) x = B S K g x = (B S K) g xこいつが fmap g xと同じになるので、fmap g x = (B S K) g xなのでfmapはまさにBSKとなっている。
Kがpure(=return)ってのは確かに、プログラムを書いていて、 引数を一個消して一階層上の関数合成のレイヤに持ち込んだときにできるDSLのconstとなるのと感覚が非常に合致している。 なんか少しスッキリ。cut-sea:2010/03/31 10:15:21 JST
ちなみにBはおなじみ(.)に相当するので、 fmap = B S K = (.) <*> return
= (<*>) . returnつまり、「fmapはreturnして(<*>)すること」と読める。 まんまです。
さらにスッキリ。cut-sea:2010/03/31 10:25:02 JST
これについてちょっと考えてみやう!
こっちね -> グローバル変数が欲しい理由?
今週いただきました。
amazonで予約したやつがまだ来てないのに。
しかし分厚いなー。
やっぱ楽しいや。
Haskellの本ってこれまでどうも学術的と思われるような本ばっかだったので、
この本は良いよー。
まさにPracticalな感じでほんきに存在意義があると思う。
この泥臭さが好きだなー。cut-sea:2008/12/05 23:53:29 JST
ゲーデル・エッシャー・バッハね。 ものまね鳥を一個スタックに積んでこちらを読む。
ものまね鳥で階数の話が出てて、 だからどうしたと思ってスルーしたりもしたが、 早速それっぽい所にヒットしたか。cut-sea:2008/11/25 22:21:03 JST
しばらくぶりに追っかけ。
とおもったらエラーが発生。
patchが無いと言われた。
え?Ubuntuってデフォでpatch入ってないの?
しょうがないのでパッケージシステムからインストールして、再度ビルド中。 今度はちゃんと最後まで行くんだろうか。cut-sea:2008/11/12 22:57:50 JST
やっぱりことあるごとに他人にアピールしておくものだ。
声を掛けてた人が区の図書館から、この本を入手して「カリーの森」は難しくなかったよ言って少し説明してくれた。
分ったわけじゃないけど、とりあえず予想通り、ゲーデルとか数学の世界で起った数学基礎論とか、
歴史的な経緯とかの知識があった方が分りやすいだろうね、ということに。
で、その人が言うには「ゲーデル・エッシャー・バッハ」が一番分りやすかったとのことで、
あのイエローページみたいなやつかと少し萎え萎えなんだが、読んでみるかなぁと。
ちなみにその人は数学科出身。cut-sea:2008/11/12 22:16:32 JST
カリーの森で足止め。
議論のあたりを誰か説明してくれー。cut-sea:2008/10/21 10:00:35 JST
なんと、ようやくスマリヤンがなぜこのような比喩を使ったのかが解った。
この様な、というのは「鳥に呼び掛けたら鳥の名前を応える」というやつ。
「ものまね鳥をまねる」でググるとamazonを除けば 背徳的なものまね鳥なんかが結構最初の方に引っ掛かって、 私もその方が何か分りやすそう、とか思ってたんだけどカリーの森でナゾが解ける。
残念ながら「鳥が交尾して鳥を産む」という比喩はヒッジョーにマズい。 これは破綻しちゃうんだ。スゲー!やっぱちゃんと考えられた比喩だったんだ。cut-sea:2008/10/15 10:09:25 JST
激ムズ。
少し調べてみたんだけど、こんな難問出すなー。cut-sea:2008/10/14 10:17:41 JST
賢人鳥の章も終えた。
結構これもK的な簡単さがあったな。
問題も読んだ瞬間になんだか自明というか、
単に言い換えてるだけというか、
そういう簡単な感じがする。
で、今朝はそのままカリーの森に突入。
まだはっきりとはしないけど、コンビネータにその森特有の意味を持たせて、
ロジックを築いていく(?)という応用編に突入ということでいいかな?
第IV部ということで、ここで部がかわったし。cut-sea:2008/10/10 09:59:37 JST
Oが面白い。
へたすりゃ賢人鳥Θより興味深いかも。
ちなみに、ΘはΘx=x(Θx)ね。OはOxy=y(xy)である。cut-sea:2008/10/09 13:46:37 JST
賢人鳥系の問題をはじめてるけど、最初はとっかかりが無くてなかなか解けなかった。
再帰してて自分自身が右辺にも来ちゃってるから、
以前、解いた「任意の鳥が好きな鳥」というやつの表現を使うというのは思いついたんだけど、
そのパターンが多くてノートを漁っても、なかなかすぐ見つけらんなくて解けない。
また少しずつ慣れてはきてるけど。
なんか章が変わる度に毎度振り回されてる気がする。cut-sea:2008/10/08 20:31:05 JST
今日仕事で「こりゃHaskellならunfoldrだよな」って思ったんだけど、 まぁC#でforeachを使いまくってゴテゴテと書いていた。
で、帰ってからHaskellでポイントだけ再実装してみたんだけど、unfoldrだと引数が一個足りない??
module Main where
import Data.List
type ProductsId = String
type Quantity = Int
type PackLimit = Int
data OrdersProducts = Op {prod :: ProductsId, q :: Quantity} deriving (Show)
original_order :: [OrdersProducts]
original_order = [Op "A" 5, Op "B" 7, Op "C" 3, Op "D" 12, Op "E" 2, Op "F" 2, Op "G" 1]
unfoldr2 :: (b -> c -> Maybe(a,b,c)) -> b -> c -> [a]
unfoldr2 f b c =
case f b c of
Just (a,b',c') -> a : unfoldr2 f b' c'
Nothing -> []
makePlan :: PackLimit -> [OrdersProducts] -> [[OrdersProducts]]
makePlan limit = unfoldr2 breaker []
where
breaker [] [] = Nothing
breaker wk [] = Just (wk,[],[])
breaker wk (r:rs) | qt == limit = Just (wk++[r],[],rs)
| qt < limit = breaker (wk++[r]) rs
| qt > limit = Just (wk++[Op (prod r) (q r-over)],[],Op (prod r) over:rs)
where
qt = foldr ((+).q) 0 wk + q r
over = qt - limit
あーそーだ。
makePlan :: PackLimit -> ([OrdersProducts],[OrdersProducts]) -> [[OrdersProducts]]
makePlan limit = unfoldr breaker
where
breaker ([],[]) = Nothing
breaker (wk,[]) = Just (wk,([],[]))
breaker (wk,(r:rs)) | qt == limit = Just (wk++[r],([],rs))
| qt < limit = breaker ((wk++[r]),rs)
| qt > limit = Just (wk++[Op (prod r) (q r-over)],([],Op (prod r) over:rs))
where
qt = foldr ((+).q) 0 wk + q r
over = qt - limit
これでいんじゃん。アホだ。
それよか内部定義の型とかって調べられたりしないかな。 例えば
*Main> :t makePlan.breaker
みたいに。 トップレベルで実装してからwhere句に移動させるのタルいし。cut-sea
makePlan :: PackLimit -> [OrdersProducts] -> [[OrdersProducts]]
makePlan limit rs = concat $ snd $ mapAccumL f ([],0) $ map Just rs ++ [Nothing]
where
f (wks,_) Nothing = (([],0),[wks])
f (wks,t) (Just r) | t' < limit = ((wks++[r],t'),[])
| otherwise = ((wks',b),ws)
where
t' = t + q r
(a,b) = divMod t' limit
ws = [wks++[r{q=limit-t}]] ++ replicate (a-1) [r{q=limit}]
wks' = if b == 0 then [] else [r{q=b}]
makePlan :: PackLimit -> [OrderedProducts] -> [[OrderedProducts]]
makePlan n = map (compo . group) . splits n . concatMap decompo
splits :: Int -> [a] -> [[a]]
splits n = unfoldr phi
where phi [] = Nothing
phi xs = Just $ splitAt n xs
decompo :: OrderedProducts -> [ProductId]
decompo (Op i q) = replicate q i
compo :: [[ProductId]] -> [OrderedProducts]
compo = map $ uncurry Op . (head &&& length)
今朝、無事通過。
そのまま勢いで「賢人鳥のギャラリー」に突入。
ざっと先読みして太字を追うと、
1階の鳥とか固有鳥とか正規結合子とか類似性とか拡張的とかまばらであるとか
今迄の空気じゃないタームが並んでいて楽しみだ。cut-sea:2008/10/01 22:00:09 JST
やられた。
これまでも誤字はあったものの、読んでて気付くレベルだった。
まさか問題が間違ってるとはなぁ。
長く悩んでどうにも降参しちゃって答を見たんだが、直感的にはその形になる様に思えず、
答から逆算してみたら案の定問題が間違ってやがった。
今日は1問すら進まなかったよ。
今朝の段階で今の章が終わると思ってたのに。cut-sea:2008/09/30 22:40:07 JST
なるほど。
当り前なんだけど、重複している引数を1つに消し込みたかったら、
やはり重複効果のある鳥を使えばよいんだ。cut-sea:2008/09/24 12:39:11 JST
今日から重複効果のある鳥なんだけど、以前より使って良い鳥が増えた分、むしろ簡単かもしれん。
それでいて、自明っぽい問題じゃないから面白い。
なんとなく、よりハイレベルのユーティリテュがあるおかげで以前より難しいはずの問題がさらっと解ける感じDeath。
だけど、ある鳥を別の鳥で表現することにあまり意味を感じなくなってきた。
ちょっと誤解をまねきそうなので補足すると、ある鳥がB系とT系で表現できるとか
M系を必要とするかなどを理解する(ちゅーか直感的に判る感覚を身に付ける)のはいいと思うんだけど、
だからと言ってRを使って表現したかCを使って表現したかなどはどーでもいーよなーっとか。
ただ手を動かして解くことでたまに発見することや理解したと思えることがちょこちょこ出てくるので、 パスるのも良くないよなーってことで、ちまちまと問題と格闘してしまうのであった。cut-sea:2008/09/22 10:40:59 JST
今朝ようやく多数の鳥が登場する章をくぐり抜けたのであった。 最初戸惑ったflip系の変換も慣れると意外とサクサク解ける。 それでも少し頭を捻らなきゃならないレベルだったので楽しめた。
で、来週から何かと言うと「ものまね鳥、ウグイス、ホシムクドリ」というわけで重複効果ですな。 つまりこれで結合、置換、複製の各パターンが出揃うわけだ。 その次に来るのは「賢人鳥のギャラリー」ってことで、再帰系だ。 Yだけはすでに出てきてたけど、再帰パターンになる鳥の仲間だっけかな。(テキトー)
そこまででようやく基本のキが終わるようなもんだろうか。長ぇ。cut-sea:2008/09/20 00:16:15 JST
今度は最近完成したとのアナウンスが流れ、amazonでも予約できるようになっているReal World Haskellで紹介されているGtk2HS。
とりあえず片っ端からパッケージでlib系を入れておいてからINSTALLドキュメントに従ってインストールしたらサンプルプログラムが結構サクッと動作した。
こっちのがドキュメントやらサンプルやらがあっていいかも。cut-sea:2008/09/18 03:16:30 JST
HaskellでGUIを書こうとした場合に何が最短だろうか?と調べたらwxHaskellっぽい?
開発が止まってるという話を聞いたんだけど、今もソースは更新されてるみたいなのでいいんじゃないかしらん。
とりあえずwxcoreとwxをインストールしたら無事サンプルが動作。
wxWidgetを2.8が最新だったもんだから最初それを使ってたんだけど、どうにもエラーが出てまともに起動せず。
wxHaskellの方のchangesを見たら2.6への適合はやったとあるが、それが最後の模様。
というわけで2.6にダウングレードしてwxcore/wxの再インストールをした次第。cut-sea:2008/09/17 23:42:06 JST
自分が導出した式と回答にある式の相互変換をするために少し時間がかかったけど、うまくつながった。
解けるとどうということはないが、案外気付かないものかも。
これまでも何度か経験したことではあるんだけど、
見えないものが見えるようになった瞬間というのは結構うれしい。cut-sea:2008/09/17 07:00:08 JST
B系の結合鳥をやってて、これは結構簡単だったんで油断してた。
この2、3日はRとかCとかFなどの置換鳥をやってるんだが、これが結構難しい。
コツらしきものを掴んだと思ったら次の問題ではうまくいかないし、 これは答だろうと思って到達しても回答にあるのと形が違ってると、 さらにそれが対応するのか確認しないとどうも気持ち悪いしってことでやってるんだが、 結合鳥の時と違って結構対応確認も手間取るしで、遅々として進まない。
多分全体から見ると今は一番つまらない箇所なんだろうけど、
それでも結構楽しんでやれているのは幸いだ。
まだまだ問題がいっぱいあるので、いつこの森を抜けられるのか分らんが、
パズルを解くのが直接の目的じゃないのでじっくりやる。cut-sea:2008/09/13 23:50:59 JST
ようやく大勢の鳥たちがぞくぞくと登場する章に突入。 さっそくルリツグミB登場。 今朝解いた問題は以前証明したものをBも利用して再証明するということで、 だいぶパターンに慣れてきた感じ。cut-sea:2008/09/05 10:03:39 JST
ようやく最初の章がおわった。
ここまでで登場した鳥は、M,I,L,K。(ミルク?)
難しいので、解けない問題は答を見て、翌日再チャレンジでやってる。
KとかIの問題は簡単なんだが、MとLが絡む問題は思いつく必要がある(今のところ?)ことがあって、
どうにも解けなかったりする。
トータルで今までのところ3問くらいは自力で解けなかったかな。
とりあえず今日ようやく賢人鳥が登場した。
賢人鳥はいわゆるYコンビネータ。
本書の比喩では「xの名を呼びかけるとxが好む鳥の名を語って答えてくれる鳥」。。。
なんだけど、これって本当に答えてくれてるのか??
で、ここは1問だけなんだけど、問題に取りかかる前に、早速MとLの関係に悩み中。cut-sea:2008/09/03 10:25:24 JST
今朝は結構すんなり2問目が解けた。 すんなりっていってもメモ用紙3枚くらいに色々書いてゴミにしたけど。
あとTo Dissect a Mockingbirdってのが結構いい。 印刷して読んでみているところ。cut-sea:2008/08/13 10:27:57 JST
ざっと一通りは読んだが、読んだだけーなので、
今度は改めて問題を解いていく。
手を動かして進めましょうということでノートを購入。
朝食を取りながら一問目に挑戦するも…。orz
やっぱムズイ。cut-sea:2008/08/12 10:09:08 JST
少しずつ、おもしろくなってきた。
SとKってなんかイビツな基本の結合子だと思ってたけど、
なるほど、そういうことかとナットク。
いろんな結合子が無数に作れる中で、
引数の複製と消滅という特異な機能をもっているってのがまず第一にある模様。
じゃあ他のでもいいじゃんとなりそうだが、実際そうらしく、
何を基本の結合子として全てを表現するかという試みは、
それはそれでいくつものパターンでやっているみたい。
しかしその中でなぜSとKがこうも有名なのかというのは、まだちょっと分ってない。cut-sea:2008/07/25 02:34:23 JST
入手。
昨日GaucheFestから帰ったら来てた。
さっそく読みはじめたが、こりゃ紙とエンピツが必需品だな。
ひさびさに筆記用具をとりだしてちまちまとはじめたが、
裏紙じゃなくて、ノートが欲しくなってきた。どしよ。cut-sea:2008/07/21 00:01:56 JST
なんだけどHaskellで書いてた。
逆にnobsunはGauche?で。
とりあえず(<*>)と(&&&)を使った処理をfirst sketchでポイントフリー的に考えられるようになりつつある。
ただ、考え方それ自体はともかく、実際にパラった時に複数の流れの
どれがどうなってたか一度に頭の中に置いておけないんだよなぁ。
(<*>) :: (a->b->c) -> (a->b) -> (a->c) (f <*> g) x = f x $ g x (<.>) :: (a->b) -> (a->c) -> (a->(b,c)) (f <.> g) x = (f x, g x)
利用するコンビネータとしてB以外では上記の2つを用意。 上のは(<*>)=Sで下のは(&&&)でControl.Applicativeにあるけど、 今回はとりあえず自作した。 (<.>)としたのは、あとから(&&&)がそうだったんだと知っただけ。
で、
(<->) :: Gate -> Gate -> Gate f <-> g = g.((++).fst<*>snd).f (<|>) :: Gate -> Gate -> Gate f <|> g = (((++).fst<*>fst.g.snd)<.>(snd.g.snd)).f
こんな感じのコードを以前だったらリファクタリングの結果として到達することはあったけど、 なんとか考えながらではあるものの書き下せるようになってきてる。
上記のは一応
infixr 4 <|> infixr 5 <-> infixr 6 <.> infixr 7 <*>
としてる。 cut-sea:2008/07/19 17:38:54 JST
インストールしてみて分ったけど、ghc-pkg listがえらく不足してた。
tar zxvf ~/POOL/Haskell/ghc-6.8.3-src.tar.bz2 tar zxvf ~/POOL/Haskell/ghc-6.8.3-src-extralibs.tar.bz2
の両方を展開しておいてから./configure+mk/config.mk編集+gmakeで
cut-sea@nkisi> ghc-pkg list
/usr/local/lib/ghc-6.8.3/package.conf:
Cabal-1.2.4.0, HUnit-1.2.0.0, QuickCheck-1.1.0.0, array-0.1.0.0,
base-3.0.2.0, bytestring-0.9.0.1.1, cgi-3001.1.6.0,
containers-0.1.0.2, directory-1.0.0.1, fgl-5.4.2.0,
filepath-1.1.0.0, (ghc-6.8.3), haskell-src-1.0.1.2,
haskell98-1.0.1.0, hpc-0.5.0.1, html-1.0.1.1, mtl-1.1.0.1,
network-2.2.0.0, old-locale-1.0.0.0, old-time-1.0.0.0,
packedstring-0.1.0.0, parallel-1.0.0.1, parsec-2.1.0.1,
pretty-1.0.0.0, process-1.0.0.1, random-1.0.0.0,
regex-base-0.72.0.1, regex-compat-0.71.0.1, regex-posix-0.72.0.2,
rts-1.0, stm-2.1.1.1, template-haskell-2.2.0.0, time-1.1.2.1,
unix-2.3.0.1, xhtml-3000.2.0.0
なレベルでなかなかよさげ。 あとは自分でHackageDBから持ってくるか。 ただ、インストール先がどうにも気に入らないので、そこを調べてからかなぁ。cut-sea:2008/07/04 07:52:57 JST
./configureした後にmk/config.mkを手でいじった。
#----------------------------------------------------------------------------- # GMP Library (version 2.0.x or above) # HaveLibGmp = YES LibGmp = installed GMP_INCLUDE_DIRS=/usr/pkg/include GMP_LIB_DIRS=/usr/pkg/lib
あまりよくわかってないけど、上記のように編集してからgmakeすると以下のようにgmpを一応リンクしてくれた。
ghc-6.8.3:
-lc.12 => /usr/lib/libc.so.12
-lutil.7 => /usr/lib/libutil.so.7
-lm.0 => /usr/lib/libm387.so.0
-lm.0 => /usr/lib/libm.so.0
-lgmp.3 => /usr/pkg/lib/libgmp.so.3
-lrt.0 => /usr/lib/librt.so.0
-lpthread.0 => /usr/lib/libpthread.so.0
ああ、ちなみにbuildしたやつをinstall済みなので、 現在buildに使われているghcはもうghc-6.8.3になってる。cut-sea:2008/07/02 07:56:29 JST
/usr/local/include以下にgmp.hを入れたり、gmpを先にビルドしてinstallしておいてからやったりしたけどそれはダメだった。
その後、いくつかいじってしまったので 現在再確認のためまたまた条件を絞ってビルド中だけど、 今朝起きたらビルドできてたっぽいのでメモ。
GHC-6.8.3のビルドをするにあたり、システムには動くGHCが必要なわけだけど、 そいつが私の環境の場合にはpkgsrcというNetBSDのパッケージシステムから入れたものである。 具体的にはghc-6.8.2という直前のversionが入っているので、そいつを利用してビルドすることになるんだと思う。
で、まずそのGHCについてなんだけど、
/usr/pkg/lib/ghc-6.8.2というディレクトリにGHCのすべてのファイルが入っているようだ。
例えば/usr/pkg/bin/ghcなんかは/usr/pkg/lib/ghc-6.8.2/ghc-6.8.2というexeにシンボリックリンクされているし、
/usr/pkg/lib/ghc-6.8.2/incldueやらlibやらがある構成になっている。
ただし、pkgsrcでビルドした際にどうやらgmpはgmpで別にインストールしているから、
GHCとしてはそいつを利用する方向でビルド&インストールしたんだろう。
正しい姿がどうなのか知らないけど、
gmpを別のpkgsrcからインストールされたものを
利用したせいじゃないかと思うんだけど
/usr/pkg/lib/ghc-6.8.2/include配下にgmp.hが無いというのが直接の問題のようだ。
つまり、ここにgmp.hがあれば良いとうことのようで、
ln -s /usr/pkg/include/gmp.h /usr/pkg/lib/ghc-6.8.2/include/gmp.hとして
おいてやるとビルドに成功するというオチっぽい
(これだけなのかどうかを現在再確認中)。
これなら./configure;gmakeで問題ないみたいだ。cut-sea:2008/06/28 08:00:31 JST
とりあえずビルド自体はおっけーそうだ。 ちなみにmake installもgmake installじゃないと通らなかった。これは初めての体験かも。 しかし足りない。 pkgsrcから入れたのが
root@nkisi> ldd /usr/pkg/lib/ghc-6.8.2/ghc-6.8.2
/usr/pkg/lib/ghc-6.8.2/ghc-6.8.2:
-lc.12 => /usr/lib/libc.so.12
-ltermcap.0 => /usr/lib/libtermcap.so.0
-lreadline.5 => /usr/pkg/lib/libreadline.so.5
-lutil.7 => /usr/lib/libutil.so.7
-lm.0 => /usr/lib/libm387.so.0
-lm.0 => /usr/lib/libm.so.0
-lgmp.3 => /usr/pkg/lib/libgmp.so.3
-lrt.0 => /usr/lib/librt.so.0
-lpthread.0 => /usr/lib/libpthread.so.0
root@nkisi>
に対して
root@nkisi> ldd ghc-6.8.3
ghc-6.8.3:
-lc.12 => /usr/lib/libc.so.12
-lutil.7 => /usr/lib/libutil.so.7
-lm.0 => /usr/lib/libm387.so.0
-lm.0 => /usr/lib/libm.so.0
-lrt.0 => /usr/lib/librt.so.0
-lpthread.0 => /usr/lib/libpthread.so.0
である。 --with-gmp-includesと--with-gmp-librariesの両オプションを付けても結果は同じ。 termcapとreadlineはともかくgmpが見られてないのはどうもマズいんでないの?と思うんだけどどうなんでしょう?cut-sea:2008/06/28 09:21:35 JST
うまくいくかどうかはわからんがメモっていく。
#! /usr/bin/perl -wとなってるので
#! /usr/pkg/bin/perl -wと修正しておく。
cut-sea@nkisi> ./darcs-all pull -a == running darcs pull -a Pulling from "http://darcs.haskell.org/ghc"... This is the GHC darcs repository (HEAD branch) For more information, visit the GHC developer wiki at http://hackage.haskell.org/trac/ghc ********************** No remote changes to pull in! == nofib not present or not a repository; skipping == running darcs pull -a --repodir testsuite Pulling from "http://darcs.haskell.org/testsuite"... This is the GHC testsuite darcs repository (HEAD branch) For more information, visit the GHC developer wiki at http://hackage.haskell.org/trac/ghc ********************** Finished pulling and applying. == running darcs pull -a --repodir libraries/array Pulling from "http://darcs.haskell.org/packages/array"... Finished pulling and applying. == running darcs pull -a --repodir libraries/base Pulling from "http://darcs.haskell.org/packages/base"... Finished pulling and applying. == running darcs pull -a --repodir libraries/bytestring Pulling from "http://darcs.haskell.org/packages/bytestring"... Finished pulling and applying. == running darcs pull -a --repodir libraries/Cabal Pulling from "http://darcs.haskell.org/packages/Cabal"... This is GHC's branch of the main Cabal repo. NB. DO NOT push new Cabal patches to this repo, instead use the main Cabal repo at http://darcs.haskell.org/cabal Patches to this repo must pass GHC's validate script before being pushed. ********************** No remote changes to pull in! == running darcs pull -a --repodir libraries/containers Pulling from "http://darcs.haskell.org/packages/containers"... Finished pulling and applying. == running darcs pull -a --repodir libraries/directory Pulling from "http://darcs.haskell.org/packages/directory"... Finished pulling and applying. == running darcs pull -a --repodir libraries/editline Pulling from "http://darcs.haskell.org/packages/editline"... Finished pulling and applying. == running darcs pull -a --repodir libraries/filepath Pulling from "http://darcs.haskell.org/packages/filepath"... Finished pulling and applying. == running darcs pull -a --repodir libraries/ghc-prim Pulling from "http://darcs.haskell.org/packages/ghc-prim"... Finished pulling and applying. == running darcs pull -a --repodir libraries/haskell98 Pulling from "http://darcs.haskell.org/packages/haskell98"... No remote changes to pull in! == running darcs pull -a --repodir libraries/hpc Pulling from "http://darcs.haskell.org/packages/hpc"... No remote changes to pull in! == running darcs pull -a --repodir libraries/integer-gmp Pulling from "http://darcs.haskell.org/packages/integer-gmp"... Finished pulling and applying. == running darcs pull -a --repodir libraries/old-locale Pulling from "http://darcs.haskell.org/packages/old-locale"... Finished pulling and applying. == running darcs pull -a --repodir libraries/old-time Pulling from "http://darcs.haskell.org/packages/old-time"... Finished pulling and applying. == running darcs pull -a --repodir libraries/packedstring Pulling from "http://darcs.haskell.org/packages/packedstring"... Finished pulling and applying. == running darcs pull -a --repodir libraries/pretty Pulling from "http://darcs.haskell.org/packages/pretty"... Finished pulling and applying. == running darcs pull -a --repodir libraries/process Pulling from "http://darcs.haskell.org/packages/process"... Finished pulling and applying. == running darcs pull -a --repodir libraries/random Pulling from "http://darcs.haskell.org/packages/random"... Finished pulling and applying. == running darcs pull -a --repodir libraries/template-haskell Pulling from "http://darcs.haskell.org/packages/template-haskell"... Finished pulling and applying. == running darcs pull -a --repodir libraries/unix Pulling from "http://darcs.haskell.org/packages/unix"... Finished pulling and applying. == running darcs pull -a --repodir libraries/Win32 Pulling from "http://darcs.haskell.org/packages/Win32"... No remote changes to pull in! cut-sea@nkisi>ずらずらとこんな感じでしばらくしたら終了。
cut-sea@nkisi> ./darcs-all --extra get warning: adding --partial, to override use --complete warning: array already present; omitting warning: base already present; omitting warning: bytestring already present; omitting warning: Cabal already present; omitting warning: containers already present; omitting warning: directory already present; omitting warning: editline already present; omitting warning: filepath already present; omitting warning: ghc-prim already present; omitting warning: haskell98 already present; omitting warning: hpc already present; omitting warning: integer-gmp already present; omitting warning: old-locale already present; omitting warning: old-time already present; omitting warning: packedstring already present; omitting warning: pretty already present; omitting warning: process already present; omitting warning: random already present; omitting warning: template-haskell already present; omitting warning: unix already present; omitting warning: Win32 already present; omitting == running darcs get --partial http://darcs.haskell.org/packages/ALUT Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/GLUT Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/HUnit Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/ObjectIO Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/OpenAL Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/OpenGL Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/QuickCheck Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/cgi Copying patch 3 of 3... done. Applying patch 2 of 2... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/fgl Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/haskell-src Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/html Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/mtl Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/network Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/parsec Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/parallel Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/regex-base Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/regex-compat Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/regex-posix Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/stm Copying patch 3 of 3... done. Applying patch 2 of 2... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/time Copying patch 3 of 3... done. Applying patch 2 of 2... done. Finished getting. == running darcs get --partial http://darcs.haskell.org/packages/xhtml Copying patch 2 of 2... done. Applying patch 1 of 1... done. Finished getting. cut-sea@nkisi>
warning: adding --partial, to override use --complete warning: testsuite already present; omitting warning: array already present; omitting warning: base already present; omitting warning: bytestring already present; omitting warning: Cabal already present; omitting warning: containers already present; omitting warning: directory already present; omitting warning: editline already present; omitting warning: filepath already present; omitting warning: ghc-prim already present; omitting warning: haskell98 already present; omitting warning: hpc already present; omitting warning: integer-gmp already present; omitting warning: old-locale already present; omitting warning: old-time already present; omitting warning: packedstring already present; omitting warning: pretty already present; omitting warning: process already present; omitting warning: random already present; omitting warning: template-haskell already present; omitting warning: unix already present; omitting warning: Win32 already present; omitting cut-sea@nkisi>すでにあるから端折ったよってことらしい。
cut-sea@nkisi> ./darcs-all --nofib get warning: adding --partial, to override use --complete == running darcs get --partial http://darcs.haskell.org/nofib This is the nofib darcs repository (HEAD branch) For more information, visit the GHC developer wiki at http://hackage.haskell.org/trac/ghc ********************** Copying patch 3 of 3... done. Applying patch 2 of 2... done. Finished getting. warning: array already present; omitting warning: base already present; omitting warning: bytestring already present; omitting warning: Cabal already present; omitting warning: containers already present; omitting warning: directory already present; omitting warning: editline already present; omitting warning: filepath already present; omitting warning: ghc-prim already present; omitting warning: haskell98 already present; omitting warning: hpc already present; omitting warning: integer-gmp already present; omitting warning: old-locale already present; omitting warning: old-time already present; omitting warning: packedstring already present; omitting warning: pretty already present; omitting warning: process already present; omitting warning: random already present; omitting warning: template-haskell already present; omitting warning: unix already present; omitting warning: Win32 already present; omitting cut-sea@nkisi>
cut-sea@nkisi> sh boot Booting . configure.ac:904: warning: AC_CACHE_VAL(fp_gcc_version, ...): suspicious cache-id, must contain _cv_ to be cached ../../lib/autoconf/general.m4:1973: AC_CACHE_VAL is expanded from... ../../lib/autoconf/general.m4:1993: AC_CACHE_CHECK is expanded from... aclocal.m4:548: FP_HAVE_GCC is expanded from... configure.ac:904: the top level configure.ac:904: warning: AC_CACHE_VAL(fp_gcc_version, ...): suspicious cache-id, must contain _cv_ to be cached ../../lib/autoconf/general.m4:1973: AC_CACHE_VAL is expanded from... ../../lib/autoconf/general.m4:1993: AC_CACHE_CHECK is expanded from... aclocal.m4:548: FP_HAVE_GCC is expanded from... configure.ac:904: the top level configure.ac:904: warning: AC_CACHE_VAL(fp_gcc_version, ...): suspicious cache-id, must contain _cv_ to be cached ../../lib/autoconf/general.m4:1973: AC_CACHE_VAL is expanded from... ../../lib/autoconf/general.m4:1993: AC_CACHE_CHECK is expanded from... aclocal.m4:548: FP_HAVE_GCC is expanded from... configure.ac:904: the top level Booting libraries/ALUT Booting libraries/GLUT Booting libraries/OpenAL Booting libraries/OpenGL Booting libraries/base Booting libraries/directory /usr/pkg/share/aclocal/rep.m4:7: warning: underquoted definition of AM_PATH_REP /usr/pkg/share/aclocal/rep.m4:7: run info '(automake)Extending aclocal' /usr/pkg/share/aclocal/rep.m4:7: or see http://sources.redhat.com/automake/automake.html#Extending-aclocal Booting libraries/editline Booting libraries/network Booting libraries/old-time Booting libraries/process Booting libraries/regex-posix Booting libraries/time Booting libraries/unix configure.ac:67: warning: AC_CACHE_VAL(cv_func_usleep_return_type, ...): suspicious cache-id, must contain _cv_ to be cached ../../lib/autoconf/general.m4:1973: AC_CACHE_VAL is expanded from... ../../lib/autoconf/general.m4:1993: AC_CACHE_CHECK is expanded from... configure.ac:67: the top level configure.ac:67: warning: AC_CACHE_VAL(cv_func_usleep_return_type, ...): suspicious cache-id, must contain _cv_ to be cached ../../lib/autoconf/general.m4:1973: AC_CACHE_VAL is expanded from... ../../lib/autoconf/general.m4:1993: AC_CACHE_CHECK is expanded from... configure.ac:67: the top level configure.ac:67: warning: AC_CACHE_VAL(cv_func_usleep_return_type, ...): suspicious cache-id, must contain _cv_ to be cached ../../lib/autoconf/general.m4:1973: AC_CACHE_VAL is expanded from... ../../lib/autoconf/general.m4:1993: AC_CACHE_CHECK is expanded from... configure.ac:67: the top level cut-sea@nkisi>いくつかwarningが出てるけど、errorとかではないんでいいのかな。
/usr/pkg/bin/ghc -optc-O -optc-Iparser -optc-I. -optc-O -H32m -O -istage1/utils -istage1/basicTypes -istage1/types -istage1/hsSyn -istage1/prelude -istage1/rename -istage1/typecheck -istage1/deSugar -istage1/coreSyn -istage1/vectorise -istage1/specialise -istage1/simplCore -istage1/stranal -istage1/stgSyn -istage1/simplStg -istage1/codeGen -istage1/main -istage1/profiling -istage1/parser -istage1/cprAnalysis -istage1/iface -istage1/cmm -istage1/nativeGen -Wall -fno-warn-name-shadowing -fno-warn-orphans -Istage1 -cpp -fglasgow-exts -Rghc-timing -I. -Iparser -Iutil -fno-generics -package unix -ignore-package lang -Rghc-timing -H16M '-#include "cutils.h"' -DUSING_COMPAT -i../compat -ignore-package Cabal -package directory -package pretty -package containers -c parser/cutils.c -o stage1/parser/cutils.o
In file included from /usr/pkg/lib/ghc-6.8.2/include/Stg.h:150,
from /usr/pkg/lib/ghc-6.8.2/include/Rts.h:19,
from parser/cutils.c:6:0:
/usr/pkg/lib/ghc-6.8.2/include/Regs.h:28:17:
error: gmp.h: No such file or directory
In file included from /usr/pkg/lib/ghc-6.8.2/include/Stg.h:150,
from /usr/pkg/lib/ghc-6.8.2/include/Rts.h:19,
from parser/cutils.c:6:0:
/usr/pkg/lib/ghc-6.8.2/include/Regs.h:121:0:
error: expected specifier-qualifier-list before 'MP_INT'
In file included from parser/cutils.c:6:0:
/usr/pkg/lib/ghc-6.8.2/include/Rts.h:203:0:
error: expected ')' before '*' token
/usr/pkg/lib/ghc-6.8.2/include/Rts.h:204:0:
error: expected ')' before '*' token
<<ghc: 27182068 bytes, 4 GCs, 159744/159744 avg/max bytes residency (1 samples), 16M in use, 0.00 INIT (0.00 elapsed), 0.05 MUT (0.37 elapsed), 0.02 GC (0.07 elapsed) :ghc>>
gmake[1]: *** [stage1/parser/cutils.o] エラー 1
gmake: *** [stage1] エラー 1
cut-sea@nkisi>
というわでエラーでストップ。
やっぱりgmp.hがみつからないと言われる。
cut-sea@nkisi> ll /usr/pkg/include/gmp.h -r--r--r-- 1 root wheel 82613 Apr 19 08:48 /usr/pkg/include/gmp.h cut-sea@nkisi>こいつが分らないのか、それともソースツリーにあるgmpディレクトリ下のが見つからないと言ってるのか(後者はないだろうと思うけど)。
/usr/pkg/bin/ghc -H32m -O -istage1/utils -istage1/basicTypes -istage1/types -istage1/hsSyn -istage1/prelude -istage1/rename -istage1/typecheck -istage1/deSugar -istage1/coreSyn -istage1/vectorise -istage1/specialise -istage1/simplCore -istage1/stranal -istage1/stgSyn -istage1/simplStg -istage1/codeGen -istage1/main -istage1/profiling -istage1/parser -istage1/cprAnalysis -istage1/iface -istage1/cmm -istage1/nativeGen -Wall -fno-warn-name-shadowing -fno-warn-orphans -Istage1 -cpp -fglasgow-exts -Rghc-timing -I. -Iparser -Iutil -fno-generics -package unix -ignore-package lang -Rghc-timing -H16M '-#include "cutils.h"' -DUSING_COMPAT -i../compat -ignore-package Cabal -package directory -package pretty -package containers -c utils/Interval.hs -o stage1/utils/Interval.o -ohi stage1/utils/Interval.hi
<<ghc: 47759964 bytes, 7 GCs, 108544/159744 avg/max bytes residency (2 samples), 19M in use, 0.00 INIT (0.00 elapsed), 0.09 MUT (0.43 elapsed), 0.02 GC (0.04 elapsed) :ghc>>
/usr/pkg/bin/ghc -optc-O -optc-Iparser -optc-I. -optc-O -H32m -O -istage1/utils -istage1/basicTypes -istage1/types -istage1/hsSyn -istage1/prelude -istage1/rename -istage1/typecheck -istage1/deSugar -istage1/coreSyn -istage1/vectorise -istage1/specialise -istage1/simplCore -istage1/stranal -istage1/stgSyn -istage1/simplStg -istage1/codeGen -istage1/main -istage1/profiling -istage1/parser -istage1/cprAnalysis -istage1/iface -istage1/cmm -istage1/nativeGen -Wall -fno-warn-name-shadowing -fno-warn-orphans -Istage1 -cpp -fglasgow-exts -Rghc-timing -I. -Iparser -Iutil -fno-generics -package unix -ignore-package lang -Rghc-timing -H16M '-#include "cutils.h"' -DUSING_COMPAT -i../compat -ignore-package Cabal -package directory -package pretty -package containers -c parser/cutils.c -o stage1/parser/cutils.o
In file included from /usr/pkg/lib/ghc-6.8.2/include/Stg.h:150,
from /usr/pkg/lib/ghc-6.8.2/include/Rts.h:19,
from parser/cutils.c:6:0:
/usr/pkg/lib/ghc-6.8.2/include/Regs.h:28:17:
error: gmp.h: No such file or directory
In file included from /usr/pkg/lib/ghc-6.8.2/include/Stg.h:150,
from /usr/pkg/lib/ghc-6.8.2/include/Rts.h:19,
from parser/cutils.c:6:0:
/usr/pkg/lib/ghc-6.8.2/include/Regs.h:121:0:
error: expected specifier-qualifier-list before 'MP_INT'
In file included from parser/cutils.c:6:0:
/usr/pkg/lib/ghc-6.8.2/include/Rts.h:203:0:
error: expected ')' before '*' token
/usr/pkg/lib/ghc-6.8.2/include/Rts.h:204:0:
error: expected ')' before '*' token
<<ghc: 27177664 bytes, 4 GCs, 159744/159744 avg/max bytes residency (1 samples), 16M in use, 0.00 INIT (0.00 elapsed), 0.04 MUT (0.65 elapsed), 0.02 GC (0.03 elapsed) :ghc>>
gmake[1]: *** [stage1/parser/cutils.o] エラー 1
gmake: *** [stage1] エラー 1
cut-sea@nkisi>
うーん。やっぱ見つからないっていわれる。時間がかかったのはgmpのbuildがはいったからかな。
先日のは
(<*|*>) :: (Monad m) => (a -> c) -> (a -> m b) -> (a -> m (c, b)) g <*|*> f = uncurry (=<<) . ((return.).(,).g &&& f)
だったけど、今度は両方mつき。
(Monad m) => (a -> m b) -> (a -> m c) -> (a -> m (b, c))
これが望み。 ちゅーわけで実装したら、
(<*&*>) :: (Monad m) => (a -> m b) -> (a -> m c) -> (a -> m (b, c)) (<*&*>) f g x = f x >>= (\y -> (g x >>= (\z -> return (y , z))))
これが分りやすかったやつだけど、なんとかコンビネータつかって理解しようと思ったら
f <*&*> g = (=<<).((<*>).(((=<<).(return.).(,)).).(const id) <*> (const . g)) <*> f
まるでいみふめー。
さらに欲しいのは
(Monad m,Monad m1,Monad m2) => (a -> m1 b) -> (a -> m2 c) -> (a -> m (b, c))
だったんだけど、なんか頭イタ。
m b >>= (return.).(,) / / a / \ / m c >>= +
絵で書けばこんな感じっぽい? 最初のは
m b >>= (return.).(,) / / a / \ / c ------+
こんな感じだったと思えばいいのかな。 これ見ると最初のと同じくらいスッキリ書けてもいい気がしますが、どでしょ?
f :: a -> IO b f = undefined g :: a -> Maybe b g = undefined
こうしておいて、
*FSDB> :t (return.).(,) =<< f (return.).(,) =<< f :: (Monad m) => a -> m (IO b, a)
これはもう慣れたが、
*FSDB> :t ((return.).(,) =<< f) =<< g ((return.).(,) =<< f) =<< g :: a -> (IO b, Maybe b1)
うーん。これ行けるのか?
ってことか、ああ、なるほど。
(((return.).(,)) =<< f) 'c'これは((((return.).(,)) =<< f) 'c')であって
(((return.).(,)) =<< f 'c')これは((((return.).(,)) =<< (f 'c'))だから別だった。
これが簡単にできるなら次は
(Monad m1, Monad m2, Monad m) => (m1 a, m2 b) -> m (a, b)
とかやってみたくなるな。
とか言いつつ眠いので今日はおしまい。cut-sea:2008/06/20 01:32:01 JST
(<*>)でなんとかしたいなと思ってる状況で、 片翼がMonadになってしまっているケースに遭遇。
どうなるかリファクタリングしたんだけど、書き方がどうにも納得出来ず、 というかイメージがさっぱりなので nobsunに相談したら次のコードを提示してくれた。
foo = uncurry (>>=) . (getModificationTime &&& (return.).(,))
一応収穫は(f.).gのイメージが出来た(上の(return.).(,)んとこ)ことと
あと&&&の呪文を覚えたこと。
といってもこれもSの亜種だよなぁって話だけど。
*FSDB> :t (&&&) (&&&) :: (Arrow a) => a b c -> a b c' -> a b (c, c')
あと
*FSDB> :t (***) (***) :: (Arrow a) => a b c -> a b' c' -> a (b, b') (c, c')
なんてのもあるらしい。
あ、ghcのbuildはまだ。gmp.hが見つからないって叱られる。cut-sea:2008/06/19 08:47:45 JST
整理してみると、こうなる。
(<*|*>) :: (Monad m) => (a -> c) -> (a -> m b) -> (a -> m (c, b))
g <*|*> f = uncurry (=<<) . ((return.).(,).g &&& f)
{--
*FSDB> :t (id <*|*> getModificationTime)
(id <*|*> getModificationTime) :: FilePath -> IO (FilePath, ClockTime)
*FSDB> (id <*|*> getModificationTime) "/home/cut-sea/data/mbdb/data/%78"
("/home/cut-sea/data/mbdb/data/%78",Sat Jun 14 19:24:59 JST 2008)
*FSDB> mapM (id <*|*> getModificationTime) ["/home/cut-sea/data/mbdb/data/%78"]
[("/home/cut-sea/data/mbdb/data/%78",Sat Jun 14 19:24:59 JST 2008)]
*FSDB> mapM (id <*|*> getModificationTime) ["/home/cut-sea/data/mbdb/data/%78","/home/cut-sea/data/mbdb/data/%31%32%33"]
[("/home/cut-sea/data/mbdb/data/%78",Sat Jun 14 19:24:59 JST 2008),("/home/cut-sea/data/mbdb/data/%31%32%33",Wed Jun 18 00:03:04 JST 2008)]
--}
もう一つ欲しくなってきたな。cut-sea:2008/06/19 10:03:38 JST
リリースされたのかな。
まだリリースノート見てないけど、
今回からNetBSDも正式対応されているらしいとの噂を聞いてるので、
ビルドしてみようと思ふ。cut-sea:2008/06/18 08:42:54 JST
unfoldrを使ってみた。
split p xs = unfoldr (break' p) xs
where
break' :: (a -> Bool) -> [a] -> Maybe ([a],[a])
break' p [] = Nothing
break' p xs = case break p xs of
(_,[]) -> Just (xs,[])
(ys,_:zs) -> Just (ys,zs)
しかし、こういう分割系の関数で、ことごとくseparatorが残り要素に含まれてて スゲー不便だと思うのはオレだけか?
残りデータが同じものを返してたら、 自分で頭ハネることになって二度手間だと思うんだが。
*FSDB> split (=='/') "home/cut-sea/data/mbdb" ["home","cut-sea","data","mbdb"] *FSDB> split (=='/') "/home/cut-sea/data/mbdb" ["","home","cut-sea","data","mbdb"]
どうもunfoldrはまだ良く分らん。cut-sea:2008/06/16 07:51:04 JST
Scheme?とかだとS式で設定ファイルを書いておいて、readしちゃうってのは良くやる。
data Database = Database {prefix::String, encoding::String} deriving (Show,Read)
dbParse :: String -> Database
dbParse s = (read s)::Database
dbTest :: String -> IO ()
dbTest = putStrLn . prefix . dbParse
プログラムはこんなのをロードしてみる。 でもって、
Database {prefix="/home/cut-sea/data/hogeDB", encoding="UTF-8"}
Config.hsには上記のDBの設定を書いておく。 ghcの対話環境で、
*Main> let f = readFile "Config.hs" *Main> f >>= dbTest /home/cut-sea/data/hogeDB *Main>
readとshowがread/write不変なので簡単と思ってて、まぁ上記の通りすれば、 ちゃんと設定ファイルからDatabaseのデータをコンストラクトできるんだけど、 設定ファイルにコメントを書いたりするともうダメポ。
例えばConfig.hsにdbの設定だけじゃなくてサイトの名称やらURIのベースなんかを書く場合とかでは、 getContentsで済ませられないからreadをoverrideするだけじゃなくて設定ファイルパーサを書かなきゃならないのか。 一番良いのはHaskellのコードで設定を書いておいて、ファイルのロードだけで済ませられれば良かったんだけど、 考えてみれば、それが出来るとしたら対話型インタプリタ上で定義が出来るようなものだから無理っちゃ無理なのか。cut-sea:2008/06/15 07:09:51 JST
式を一つ読むっていうreadはできないのかしらん。 まじめにパースしなきゃならんなんてこたないと思うのね。cut-sea:2008/06/14 09:05:12 JST
もしかしたら
myDatabase = Database {prefix="/home/cut-sea/data/hogeDB", encoding="UTF-8"}
としてメインプログラムでimportしるってのが常套手段なのか? なんかそれで良さげな気がしてきたな。
ただし、その設定ファイルに色んな項目を入れたらimportとかモジュール宣言が ずらずら並んでおよそ設定ファイルらしくなくなるけど。。。cut-sea:2008/06/14 09:09:50 JST
Cabalのpackage.confは人手で作成するものじゃないからかも知らんが、
リストにしてつらつら並べてるな。ただしコメントはない。
やっぱこれは設定ファイルってのとは違うよなぁ。
システムの管理ファイルだから成立してるんだ。cut-sea:2008/06/14 09:18:53 JST
正直じゃまくさい。
ここが細かいことを気にしなくても扱えるとスゲーうれしいんだけど。
どう書く.orgのnobsunの解を見ながらようやく使えそうな気配。
{-*******************************************************
{- encoding: utf-8; mode: haskell -}
File System DataBase
*******************************************************-}
module Main where
import Control.Applicative
import Network.URI
import Codec.Binary.UTF8.String
import qualified System.IO.UTF8 as U
escape = escapeURIString (const False) . encodeString
unescape = decodeString . unEscapeString
sample0 = "~url quote../ほげ"
sample1 = "!(foo*)"
main = mapM_ (U.putStrLn . ((++) . unescape <*> (" <- "++)) . escape) [sample0,sample1]
これで
*Main> main ~url quote../ほげ <- %7E%75%72%6C%20%71%75%6F%74%65%2E%2E%2F%E3%81%BB%E3%81%92 !(foo*) <- %21%28%66%6F%6F%2A%29 *Main>
エスケープしてファイル名にして問題無いものに無害化されているのと、 それをアンエスケープして元に戻せることを確認。
ちなみにEmacs上でやるときはset-buffer-file-system-encodingをutf-8に。
terminal上でもUTF-8に移行しておいて良かったーってことなのかどうか知らんけど
問題なさげ。
cut-sea@nkisi> runghc Test.hs ~url quote../ほげ <- %7E%75%72%6C%20%71%75%6F%74%65%2E%2E%2F%E3%81%BB%E3%81%92 !(foo*) <- %21%28%66%6F%6F%2A%29 cut-sea@nkisi>
fsdbを実装しようと思ったんだけど、とりあえずこれを使えば行けそうかな。cut-sea:2008/06/13 05:26:19 JST
なんとなく分ってきた。 ので、もう少し頭の中が整理できたら何か書くかも。cut-sea:2008/06/11 09:55:31 JST
ライブラリは薄いラッパーを作成中。
*Main> h1 "H1" <h1 >H1</h1 > *Main> h1 $ toHtml "Normal Header" <h1 >Normal Header</h1 > *Main> bold "BOLD" <b >BOLD</b >
となる。ちょっとだけ楽チンになる予定だろうか(自信なし)。
一旦了。
module Main where import HtmlLite import CGI myLink = anchor![(identifier "toGoogle"),(name "toGoogle"),(href "http://www.google.co.jp")]$"click here" main = cgiMain $ const $ putHtml myLink
で、
*Main> main q: Content-type: text/html; charset="UTF-8" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" ><a id="toGoogle" name="toGoogle" href="http://www.google.co.jp" >click here</a ></html >
はじめて、「あ、K!」と思えた。
というのはどーでもいくて、XHTML的にはbodyタグ必須かー。どーしよ。
便利なutilityとしてbody内部だけ書けばいいやつを追加すっかぁ?
いやいや、pageみたいなのを作るか。cut-sea
入力出力はUTF-8のライブラリでwrapしないと、うれしさ半分だな。 もっかい使い方を調べてみるか。
って書いたけど、nobsun:utf8にあんじゃん。
ただし今のバージョンだとライブラリパスが少し変ったらしいので、
import System.IO.UTF8 -- ここ変更になった
import Prelude hiding (getContents,getLine,readFile
,putStr,putStrLn,writeFile)
import System.IO hiding (getContents,getLine,readFile
,putStr,putStrLn,writeFile
,hGetContents,hGetLine
ですね。
*Main> main お名前をどうぞ. 伊東 勝利 ようこそ,伊東 勝利さん.
おお、いけたいけた。
じゃあ例のCGIだとどうか
*Main> main q: who=%E4%BC%8A%E6%9D%B1%20%E5%8B%9D%E5%88%A9 Content-type: text/html; charset="UTF-8" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" ><h3 >こんにちわ 伊東 勝利 さん</h3 ></html >
あら、文字化けと思ってたけど、良く見たら実体参照だったのか。
クライアントからPOSTされた文字列はちゃんと自分でエスケープしてから
送らないといけなかったんだっけ。
*Main> stringToHtml "伊東 勝利" 伊東 勝利 *Main> stringToHtml "<&>" <&>
stringToHtmlは勝手にescapeしてんね。
Convert a String to Html, converting characters that need to be escaped to HTML entities.
うーん。完全にフレームワークに頼ってて基本を忘れてんなぁ。cut-sea:2008/06/10 02:59:39 JST
q: who=%3C%E4%BC%8A%E6%9D%B1+%E5%8B%9D%E5%88%A9%3E Content-type: text/html; charset="UTF-8" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" ><h3 >こんにちわ <伊東 勝利> さん</h3 ></html >
あ、ちゃんとエスケープされてる。
gosh> (use text.html-lite) #<undef> gosh> (html-escape-string "伊東 勝利") "伊東 勝利" gosh> (html-escape-string "<>") "<>" gosh> (html-escape-string "こんにちわ") "こんにちわ"
あ、そっか別にエスケープって日本語は関係ないんだっけ。
単にタグなんかになってしまう文字をエスケープするだけだ。
属性値とかでURLになってしまうようなのは別途uriencodeは必要だけど。
ってことは問題はなんでリテラルで埋め込んだ日本語だけが実体参照にしちゃうのかだけど。cut-sea:2008/06/10 03:46:10 JST
unfoldrが少し分りかけてきた。
lines' s = unfoldr f s
where
f b = if (b=="") then Nothing else Just $ break' (=='\n') b
breakでpredicateがTrueになったとこまで含めるバージョンってないすか?
spanもbreakも
*Main> break (=='\n') "Hello,\nWorld"
("Hello,","\nWorld")
*Main> span (/='\n') "Hello,\nWorld"
("Hello,","\nWorld")
って改行コードが後続に含まれてしまふのでつ。仕方なくbreak'を実装。
break' p xs = break'' [] xs
where
break'' res [] = (res, [])
break'' res (x:xs) = if p x then (res++[x],xs) else break'' (res++[x]) xs
これで
*Main> break' (=='\n') "Hello,\nWorld"
("Hello,\n","World")
ようやくlines'の実装にunfoldrに使えた。 unfoldrの感覚が掴みたかっただけだけど、えらい遠回りしてしまった。
split p xs = break'' [] xs
where
break'' res [] = (res, [])
break'' res (x:xs) = if p x then (res,xs) else break'' (res++[x]) xs
しかし我ながら話があっちゃこっちゃと…分裂気味かも。cut-sea:2008/06/10 01:53:15 JST
あ、そうそう。なんで、unfoldに話が飛んだかというと、
のでした。
よかった脈絡あった。cut-sea:2008/06/10 02:04:01 JST
Cabalのpackage.confを見てて、そういやreadは?と思ったので確認。
data Color = Red | Blue | White | RGB (Int,Int,Int) deriving (Show, Read)
ってな具合にRead classのinstanceにしておいて
*Main> read "RGB (0x7f,0x8e,0x4e)" :: Color RGB (127,142,78)
ってことでいいのね。
良かった。
設定ファイルのためのパーサを書かなくていいんだよね。
*Main> let s = (show "hoge") *Main> s "\"hoge\"" *Main> read s::String "hoge" *Main> let c = show $ RGB (0x80,0x8c,0x8c) *Main> c "RGB (128,140,140)" *Main> read c::Color RGB (128,140,140)
うむ。read/showでread/write不変ってことで再確認。cut-sea:2008/06/10 00:55:20 JST
Prelude> :t (,) (,) :: a -> b -> (a, b)
についてです。どーんと大盤振舞い。(w
Prelude> :t (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,)
(,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) :: a
-> b
-> c
-> d
-> e
-> f
-> g
-> h
-> i
-> j
-> k
-> l
-> m
-> n
-> o
-> p
-> q
-> r
-> s
-> t
-> u
-> v
-> w
-> x
-> y
-> z
-> t28
-> t29
-> t30
-> t31
-> t32
-> t33
-> t34
-> t35
-> t36
-> t37
-> t38
-> t39
-> t40
-> t41
-> t42
-> t43
-> t44
-> t45
-> t46
-> t47
-> t48
-> t49
-> t50
-> t51
-> t52
-> t53
-> t54
-> t55
-> t56
-> t57
-> t58
-> t59
-> t60
-> t61
-> t62
-> t63
-> (a,
b,
c,
d,
e,
f,
g,
h,
i,
j,
k,
l,
m,
n,
o,
p,
q,
r,
s,
t,
u,
v,
w,
x,
y,
z,
t28,
t29,
t30,
t31,
t32,
t33,
t34,
t35,
t36,
t37,
t38,
t39,
t40,
t41,
t42,
t43,
t44,
t45,
t46,
t47,
t48,
t49,
t50,
t51,
t52,
t53,
t54,
t55,
t56,
t57,
t58,
t59,
t60,
t61,
t62,
t63)
Prelude>
型がppされたー。ってツッコむトコ違うっ!
はてさて,はなんだろう? ,に,を適用して合成したわけじゃないよねぇ。
ちなみにどんだけヒマなんだと思いつつ
:t (,,,,,,,,,,,, .. ,,,,,,,,,,,)
:
t8964,
:
t8965,
:
t8966)
Prelude>
あたりまで確認。 一回に時間がかかるのでヤメた。 なにやらppもあやふやだし。
Prelude> :t (,) (,) :: a -> b -> (a, b) Prelude> :t (,,) (,,) :: a -> b -> c -> (a, b, c)
を見比べながら…
Prelude> :t (,)(,) (,)(,) :: b1 -> (a -> b -> (a, b), b1) Prelude> :t (,).(,) (,).(,) :: a -> b -> (b1 -> (a, b1), b)
うーん。(,)だけから合成して(,,)を作れるわけでもないか。
そもそも構造が別だから出来上ったものは(,)だけの組み合わせだし。
で、,って何?cut-sea:2008/06/09 23:44:47 JST
また捜してしまったのでメモ。
ghc -o app.cgi -optl-static --make App.hs
CabalによるHaskellのパ(ハ?)ッケージインストールなんだが、
runghc Setup.hs configure runghc Setup.hs build runghc Setup.hs install
とすると/usr/local/の下に入る。それはまぁいいとして、 そのディレクトリが...
/usr/local/lib/<pkg-dir>/ghc-6.8.2/...
みたいに散らかしやがるのに今気付いた。サイテー!!
ghc-6.8.2の下にまとめてくれよ、と。
冗談ぽく書いてるけど結構ムッときた。
どうにも他のアプリで共有できるものにも見えないしなぁ。
もしかしてpkgsrcでbuildしたもの(ghc-pkg)がおかしいのかしら。
それとも元々そーゆーもの?
ぐぇぇ。cut-sea:2008/06/09 23:18:24 JST--libsubdir=dir
A subdirectory of libdir in which libraries are actually installed. For example, in the simple build system on Unix, the default libdir is /usr/local/lib, and libsubdir contains the package identifier and compiler, e.g. mypkg-0.2/ghc-6.4, so libraries would be installed in /usr/local/lib/mypkg-0.2/ghc-6.4.
というわけで手で移動させたらimportできなくなった。(当然)
/usr/pkg/lib/ghc-6.8.2/packages.confにいかにもHaskellのコードっぽく
パッケージのメタデータが格納されていらっしゃるので、このパスを修正。
そしたらimportできるようになったらしい。ふう。
しかし、parsecが2.1.0.0があるのに3.0を入れてしまったんだけど、
どっちが見えることになるんだろう。
cut-sea@nkisi> ghc-pkg describe parsec
name: parsec
version: 2.1.0.0
:
ってことは2.1.0.0なんだろうか? それとも
cut-sea@nkisi> ghc-pkg latest parsec parsec-3.0.0
で3.0.0が使われるのか。 依存関係があるならイモヅルで引っ張られるのかもしれないが、 自分がimportした時はどうなるのやら。
他のパッケージのメタデータの中にも2.1.0.0の参照っぽいのが入ってるので、
気軽に削るのもマズそうだ。
メタデータ見てたらhaddockとかいうのパスには実際には何もなさげなんだけど、いーんだろうか?
つか、今頃気付いたけど、
ガイドちゃんと読めってことですね。
とりあえず6.8.3からNetBSDがサポされるらしいので、 その時には自分でbuildしようとは思ってたりする。 と、ゆーわけで早く出してたもれ。
あ、そうだ。
えらい寄り道したけど、元々DB関係のライブラリをあさってたんだった。
buildに失敗(BerkeleyDB-0.3)したり、依存するライブラリ(その他もろもろ)が多かったり、
なんか似たようなのがイロイロあるみたいに見えるんだけど、
標準でコレいっとけみたいなのはドイツだ?cut-sea:2008/06/09 22:18:57 JST
ライブラリを自作した。
Gauche?のCGIライブラリみたいに、
開発中とかでREQUEST_METHODが無い場合は
標準入力からQUERY_STRINGを受け取れるようにした。
これがやっぱり便利。
-- まずはお試し *Main> cgiMain test2 q: Content-type: text/html; charset="UTF-8" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" ><h3 >こんにちわ、あんた誰?</h3 ></html > -- クエリとしてwho=cut-seaを与えてみる *Main> cgiMain test2 q: who=cut-sea -- ← ここでqueryを与える Content-type: text/html; charset="UTF-8" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" ><h3 >こんにちわ cut-sea さん</h3 ></html > *Main>
入力出力はUTF-8のライブラリでwrapしないと、うれしさ半分だな。
もっかい使い方を調べてみるか。
以下がサンプル。
ようやくCGIが書ける準備がでけた。のか?
text/plainのサンプル
{- printenv -}
test1 req = getEnvironment >>= putText . concat . map (\(k,v)->k++" = "++v++"\n") . sort
main = cgiMain test1
text/htmlのサンプル
{- hello -}
test2 req = case getparam "who" req of
Just w -> putHtml $ h3 $ toHtml $ "こんにちわ " ++ w ++ " さん"
Nothing -> putHtml $ h3 $ toHtml "こんにちわ、あんた誰?"
main = cgiMain test1
toHtmlが邪魔くせえ。 でもinstance HTML Stringしようとしたけどムリくさかったしなぁ。cut-sea:2008/06/09 08:32:06 JST
Sコンビネータも使ってみる。
#!/usr/bin/env runghc
import System.Environment
import Data.List
import Control.Applicative
main = putStrLn "Content-type: text/plain\n\n" >> getEnvironment >>= mapM_ (putStrLn . ((++) . fst <*> (" = "++) . snd)) . sort
逆に長くなってるやんけ、と言われそうだけど、いーんです。
*Main Control.Applicative> ((*).fst<*>snd) (2,3) 6 *Main Control.Applicative> (zip<*>tail) [1..10] [(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10)] *Main Control.Applicative> (zip<*>drop 3) [1..10] [(1,4),(2,5),(3,6),(4,7),(5,8),(6,9),(7,10)]
ふーん。じゃあmyLast。
myLast n = (over <*> drop n)
where
over x [] = x
over (x:xs) (y:ys) = over xs ys
なるほど、Sコンビネータってそういうことか。 とナットク。cut-sea:2008/06/07 16:06:45 JST
over = foldl (const . tail)
こうか。
myLast n = (foldl (const . tail) <*> drop n)
なるほどね。 まだ K は全然イメージが出来てないな。cut-sea:2008/06/08 01:50:51 JST
lastn = (foldl (const . tail) <*>) . drop
もちっとらしく書いてみる。
#!/usr/bin/env runghc import System.Environment import Data.List main = putStrLn "Content-type: text/plain\n\n" >> getEnvironment >>= mapM_ (\(k,v)->putStrLn$k++" = "++v) . sort
というわけでほぼワンライナー。cut-sea:2008/06/07 12:56:24 JST
main=putStr.unlines.(unlines["Content-Type: text/plain"]:).map(uncurry((.(" = "++)).(++))).sort=<<getEnvironment
一番簡単なところから始めてみる。
#!/usr/bin/env runghc
import System.Environment
import Data.List
main = do es <- getEnvironment
putStrLn "Content-type: text/plain\n\n"
mapM_ putEnv $ sort es
where
putEnv (k,v) = putStrLn $ k ++ " = " ++ v
main = putStr . unlines . addHeader . map showEnv . sort =<< getEnvironment showEnv (k,v) = k ++ " = " ++ v addHeader = (unlines ["Content-Type: text/plain"] :)
cgiとして動かそうとするとerrorになる。 httpd/error_logにはrunghc: cannot find ghcとあるから起動時に runghcってのはどうもghcをcallしてるだけなんでしょう。 apacheから見つけらんないのかな。
% runghc --help runghc: syntax: runghc [-f GHC-PATH | --] [GHC-ARGS] [--] FILE ARG...
で、-f /usr/pkg/bin/ghc って与えるものらしいのだけど、ダメっぽい。
% ghc printenv.hs -o penv
としてバイナリをアップしておけば問題なく動作する。 最後は勿論それで良いんだけど、開発中はコンパイル面倒だな。 解決法は知らねぇ。cut-sea:2008/06/07 12:39:26 JST
朝nobsunに注文したら書いてくれたので、さっそく試してみた。
が、動かないよぉ。
悲しいのでNetwork.Socketを使って実装してみた。cut-sea:2008/06/05 05:30:42 JST
こっちね -> Programming:Network
しました。 今度は目標が見えているので最後まで頑張る。cut-sea:2008/05/24 11:00:00 JST