関数型プログラミング言語Haskell Part8
at TECH
1:デフォルトの名無しさん
07/10/30 20:28:13
haskell.org
URLリンク(www.haskell.org)
日本語サイト
URLリンク(www.sampou.org)
URLリンク(www.shido.info)
過去ログ
関数型プログラミング言語Haskell
Part1 URLリンク(pc.2ch.net)
Part2 スレリンク(tech板)
Part3 スレリンク(tech板)
Part4 スレリンク(tech板)
Part5 スレリンク(tech板)
Part6 スレリンク(tech板)
Part7 スレリンク(tech板)
・2chの仕様により、行頭の半角スペースは表示されません。
コードをインデントしたいときは、代わりに または全角スペースを使うことができます。
2:デフォルトの名無しさん
07/10/30 20:28:45
関連書籍
・Introduction to Functional Programming Using Haskell
URLリンク(www.amazon.co.jp)
・Haskell: The Craft of Functional Programming
URLリンク(www.amazon.co.jp)
・The Fun of Programming
URLリンク(www.amazon.co.jp)
・The Haskell School of Expression: Learning Functional Programming Through Multimedia
URLリンク(www.amazon.co.jp)
・入門Haskell
URLリンク(item.rakuten.co.jp)
・ふつうのHaskellプログラミング
URLリンク(item.rakuten.co.jp)
3:デフォルトの名無しさん
07/10/30 20:28:50
2
4:デフォルトの名無しさん
07/10/30 20:29:36
関連スレ
・関数型言語Part IV
スレリンク(tech板)
・【数学者】Haskellはクソ言語【オナニー】
スレリンク(tech板)
・純粋関数型言語Concurent Clean
スレリンク(tech板)
・関数型言語ML(SML, OCaml, etc.), Part 4
スレリンク(tech板)
・Lisp Scheme Part16
スレリンク(tech板)
・【入門】CommonLispその2【質問よろず】
スレリンク(tech板)
・Emacs Lisp 2
スレリンク(tech板)
5:デフォルトの名無しさん
07/10/30 20:30:11
・日本語の扱いについて
Haskell98によると、Charは一つのUnicode文字を表す(6.1.2)。
これに従って、比較的新しいHugsやGHC(6.4系を含む)ではCharは32ビット整数になっている。
ただし、どちらも入出力に際しての変換が完全でない。具体的には、
・ソースコード中の文字列リテラル
・System.IOライブラリでの入出力
が問題になる。
1. GHC6.4.2以前
ソースコード・入出力ともLatin-1を仮定する。Latin-1ではバイト値と
コードポイントが一致するので、入力時には外部エンコードの各バイトがそのままCharに
入り、出力時にはCharの下位8ビットのみが出力されるような実装になっている。
このため、あるエンコーディング(Latin-1とは限らない)の入力をgetLineで受け取り、
それをそのままputStrで表示すれば、入力時とおなじエンコードにおいて正しく表示される。
これを利用して、[Char]を、本来のコードポイントの列としてではなく、特定のエンコードの下での
バイト列として使うことができる。ただし文字列リテラルについては、GHCはLatin-1として
不正な文字を受け付けないので、EUC-JPのような例外を除くと、単純にリテラルを使うことはできない。
2. GHC6.6
ソースコードにはUTF-8、入出力にはLatin-1を仮定する。このため、EUC-JPでリテラルを直に
書くことはできない。
(続く)
6:デフォルトの名無しさん
07/10/30 20:30:47
(続き)
3.最近のHugs(非WindowsかつCのwchar_tがUnicodeの環境、というかLinux)
ソースコード・入出力ともロケールのエンコードを利用する。
4.最近のHugs(Windows)
ソースコード・入出力ともLatin-1を仮定する。ただし文字列リテラルにShift-JISを使ってもエラーにならない。
5.最近のHugs(それ以外)
未調査。
・結局どうするか。
規格どおりにCharにUnicodeを入れるか、Charを単なるバイトとして扱うかの二択。
i. CharをUnicodeとして扱う
(3)以外の場合入出力で変換が必要。(2)または(3)以外の場合文字列リテラルでは
明示的なエスケープ(たとえば"\22234")が必要。
ii. Charをバイトとして扱う
(3)ではファイルをバイナリモードで開くなどの対策が必要。(1)でEUC-JPを使う場合と(4)
を除き文字列リテラルでは明示的なエスケープ(たとえば"\143\153")が必要。
lengthやisAlphaのような関数、およびwin32パッケージの関数(win32API)が正しく動作しない。
7:1
07/10/30 20:33:11
テンプレはここまで。
前スレが終わってからしばらく建ってなかったので建てました。
初めてスレ建てしたので、行き届かないところがあったらごめんなさい。
8:デフォルトの名無しさん
07/10/30 21:15:53
乙一
9:デフォルトの名無しさん
07/10/31 01:00:13
一乙
10:デフォルトの名無しさん
07/10/31 01:32:18
4日くらい前にHaskell初めてふつけるは2回読んだんだけどモナドのとことかがよくわかんないレベルの俺が練習のためにcatコマンドの各オプションの関数作ってみた
URLリンク(uproda11.2ch-library.com) PASS:mu
であげてみたので、「この手続き脳が!」とか「貴様はなんもわかっちゃいねぇ!」とかってアドバイスしてくれると嬉しいです
あとフリーポイントスタイルの関数定義で
hogehoge = abc $ def $ ghi
hogehoeg = abc.def.ghi
↑がダメで↓がOKなのが何故なのか理解できない
.は関数合成用で$は部分適用用なの?Hoogleとかみてもよくわかんなかった
11:デフォルトの名無しさん
07/10/31 02:08:52
>>10
直した方がいいところはいろいろあるけどまずは簡単なところを一つ。
combinateStr = zipWith (++)
Preludeモジュールに入っている関数を一通り読んでおくと勉強になるよ。
12:デフォルトの名無しさん
07/10/31 07:06:57
>>11
あんがとー読んでみる
13:デフォルトの名無しさん
07/10/31 10:20:02
abc $ def $ ghi は abc(def (ghi)) と書くのと同じなので、
ghiがdefの引数になってしまう。
一方abc . def . ghi は \ x -> abc(def(ghi x))
14:デフォルトの名無しさん
07/10/31 17:00:34
>>10
headとかdrop 1とか使うよりパターンマッチの方が楽だぜ
groupEmptyLine :: [String] -> [String]
groupEmptyLine ls = case ls of
[] -> []
[]:[]:rest -> groupEmptyLine ([]:rest)
line:rest -> line : groupEmptyLine rest
createLineNumber :: Int -> [String] -> [String]
createLineNumber n ls = case ls of
[] -> []
[]:rest -> [] : createLineNumber n rest
line:rest -> (fillSpace 6 n ++ ":" ++ line) : createLineNumber (n + 1) rest
15:デフォルトの名無しさん
07/10/31 18:08:02
createLineNumber n ls = snd $ mapAccumL f n ls
where
f n "" = (n, "")
f n line = (n+1, fillSpace 6 n ++ ":" ++ line)
16:デフォルトの名無しさん
07/10/31 18:13:54
mapAccum*の引数順と渡す関数の戻り値の順序が覚えられねえ
17:デフォルトの名無しさん
07/10/31 20:22:23
>>13
よくわかんねー ためしに↓をコンパイルしてみたら怒られなかった件 …アレ?
main = do
cs <- getArgs
putStr $ test2 $ unlines cs
test1 = abc $ def $ ghi
test2 = abc.def.ghi
abc cs = cs
def cs = cs
ghi cs = cs
>>14
かっけー! なるほどー 今日一日綺麗にかけねーなーって悩んでたのがバカみたいだ
>>15
今日勉強してたんだけど
foldr←何やってるかはわかるけど何が嬉しいかはわからない
mapAccumL←意味がわからない
だったんだぜ… Hoogleで見てみてもまず引数の型に何が書いてあるかもわかんなかったんだぜ… accってなんだ…
18:デフォルトの名無しさん
07/10/31 20:53:29
>>17
Hoogleもいいけど、こっちのリファレンスなら使用例ものってるよ
URLリンク(www.zvon.org)
19:デフォルトの名無しさん
07/10/31 21:16:09
>>17
それはabc,def,ghiが全部a->a型だから通る。
例えばdef, ghiの型がInt -> Intだったらdef $ ghiってのは
引数がInt型の関数defにInt->Int型の引数ghiを突っ込むことになるので
Int ≠ Int->Intってことで型エラーになる。
20:デフォルトの名無しさん
07/10/31 21:41:32
>>17
foldrは演算子を使ってリストを潰したいときに使う。
foldr (+) 0 [1,2,3,4] = 1+(2+(3+(4+0)))
他にも、
foldr (*) 1でリスト要素の積
foldr (&&) Trueでリスト要素のAND
foldr max 0で0を下限とした最大要素
foldr union emptyで複数の集合の和集合
foldr (.) idで複数の関数の合成
など応用いっぱい。
accてのはただの型変数の名前で、aとかbとかと一緒。
21:デフォルトの名無しさん
07/10/31 22:43:13
>>18
今夜うちにきて妹をファックしていいぜ
>>19
よくわからんからあとでよく考えてみる…
>>20
なんか使いこなせば幸せになれる代物らしいことは分かった
お前らありがとな
またスレに話題がないときにでも構ってくれ ノ
22:デフォルトの名無しさん
07/10/31 23:29:45
>>17
mapAccumL のイメージ図
URLリンク(www.lab2.kuis.kyoto-u.ac.jp)
23:デフォルトの名無しさん
07/11/01 08:01:37
>>20
どれもfoldrよりfoldr1のが楽そうだな
24:デフォルトの名無しさん
07/11/01 08:07:22
>>23
maxの例はそうだけど、それ以外は空リストでも問題なく扱えるfoldrの方が使いやすくないか?
25:デフォルトの名無しさん
07/11/01 08:10:09
>>24
なるほど。納得
26:デフォルトの名無しさん
07/11/01 12:49:18
Haskellオワタ・・・
所詮おもちゃ言語か
23 名前:デフォルトの名無しさん[sage] 投稿日:2007/11/01(木) 04:45:00
darcsのスケーラビリティは改善したか?
百メガ程度のソースで、2Gでもメモリ不足でコケてどうにもならなくて泣いた。
Haskell勉強中だから応援してはいるが、Haskellユーザ以外で使ってる奴いるのか?
25 名前:デフォルトの名無しさん[] 投稿日:2007/11/01(木) 05:12:27
>>23
あれはdarcsを位置から作り直さないと直りそうもないんだけどwww
そこまでやる気あるのかな
28 名前:デフォルトの名無しさん[sage] 投稿日:2007/11/01(木) 12:47:17
>>23
それはdarcsではなくHaskellが悪い。
Haskellでは文字列のメモリ効率が悪すぎるから、あまり大きな文字列は扱えない。
27:デフォルトの名無しさん
07/11/01 13:25:07
オワタもなにも既出なんだが。
今頃気づいたのか?
28:デフォルトの名無しさん
07/11/01 20:13:54
100MBのソースコンパイルってすげーなw
誰かsequenceの説明してくれないか?
モナドがなんで便利そうなのかイメージ的にはわかったんだけど、なんでもいいけどなんかモナドをリストにして扱いたいのの具体例が思いつかね
29:デフォルトの名無しさん
07/11/01 20:59:21
説明ってsequenceが何をするか分からんってこと?
sequence [putStr "Hello", putChar ' ', putStrLn "world"]
とかすれば"Hello world\n"と表示できたり、
sequence_ $ repeat (putStrLn "hoge")
とすればhogeが無限に表示できたり。
実用例が知りたいってことならGoogle Code Searchでいくつか見つかる。
mapM(mapしてsequence)は日常的に使うけど、sequenceを単独で使うことはそれほど無い気がする。
リストモナドに適用して総当たりという使い方も一応ある。
Prelude> sequence [[1,2], [3,4,5], [6]]
[[1,3,6],[1,4,6],[1,5,6],[2,3,6],[2,4,6],[2,5,6]]
30:デフォルトの名無しさん
07/11/02 01:07:34
>>29
sequence自体が何をするのかはわかるんだけど…
google code明日にでも漁ってみるよ
分からないのは、たとえばその例だと
putStr "Hello world"で済むじゃんいらないじゃんみたいな
リストモナドに総当たりうんぬんはすごく幸せそうに見えるわ
31:デフォルトの名無しさん
07/11/02 01:23:24
>putStr "Hello world"で済むじゃんいらないじゃんみたいな
うん。だからsequenceの真価が発揮されるのはリストの内容や要素数が実行時まで決まらないときだ。
なんか人為的な例だけど、
g :: Int -> IO (Maybe (IO ())
という関数があるとする。これは何か動作を実行するんだけど、それは失敗するかもしれなくて、
そのときはNothingを返す。成功した場合は後で後始末をしなきゃいけない。そのために(Just 後始末)を返す。
gを0から9までを引数にして実行して、それが終わったら全部後始末をしたいとしよう。これはsequence_を使って
do
cleanups <- liftM catMaybes $ mapM g [0..9]
sequence_ cleanups
と書ける。
32:デフォルトの名無しさん
07/11/02 01:38:06
GHC 6.8.1がstableにupされてる
URLリンク(www.haskell.org)
33:デフォルトの名無しさん
07/11/02 20:17:45
>>31
むずかしーな…
sequence_ 〜〜のほうはわかるけどgがどんな関数なのかわからん…
時間かけて考えてみる
そして今度はStateモナドが意味わかんない件
あと>>=とかreturnも微妙によくわからない…
ふつけるP.277の
main = do g <- getStdGen
let ns = take 3 (randoms g)
-- print (ns :: [Int])
って>>=使った記法にどうやったら変形できるの?
getStdGen >>= (\g -> take 3 (randoms g)) じゃダメなの?
34:デフォルトの名無しさん
07/11/02 20:46:19
>>33
getStdGenはIOモナドだけどtake 3 (randoms g)はモナドじゃないから
return (take 3 (randoms g))にしないとだめ。
main = getStdGen >>= return . take 3 . randoms >>= (print :: [Int] -> IO ())
35:デフォルトの名無しさん
07/11/02 23:57:32
そっか!
でも\gが勝手に型推論されていい感じになったりはしないのか?
あと(print :: [Int] -> IO ()) もよくわからんから明日勉強してみるよ!
36:デフォルトの名無しさん
07/11/03 00:14:35
質問です。
前スレで↓のような宣言が書かれていたのですが、
これはどのような実装で使うことができる構文なのでしょうか?
type Hoge' = { h in Hoge | (one h) < (two h)}
37:デフォルトの名無しさん
07/11/03 00:16:45
>>28
sequenceはモナドができるまでのHaskellのIOに使われていたもので、
現在ではレガシーです。
38:デフォルトの名無しさん
07/11/03 04:20:37
>>36
その書き込みに対して「それはどういう方言?実装ある?」という
質問があったけどその後誰も反応しなかったところを見ると
ガセだったじゃないのかな。
39:デフォルトの名無しさん
07/11/04 15:38:45
またhaskell.org落ちてやがる
管理どうなってんだ
40:デフォルトの名無しさん
07/11/04 22:27:26
GHC 6.8.1リリース
URLリンク(haskell.org)
41:デフォルトの名無しさん
07/11/05 02:47:40
マニュアルの日本語訳も早くこーい
42:デフォルトの名無しさん
07/11/05 21:43:44
>>41
お前が書くんだよ
43:デフォルトの名無しさん
07/11/06 09:02:10
HaskellってGPL?
44:デフォルトの名無しさん
07/11/06 10:39:43
GHCとかHugsは非GPL。
45:デフォルトの名無しさん
07/11/06 12:17:28
どうせコンパイラいじる気がないから何でもいい
46:デフォルトの名無しさん
07/11/06 20:22:54
ちょっとお前ら教えてくれよ
>>33の続きなんだけど
@
genNRandom :: Int -> IO ()
genNRandom n = do
g <- getStdGen
let ns = take n (randoms g)
putStr $ show (ns :: [Int])
A
genNRandom :: Int -> String
genNRandom n = do
g <- getStdGen
let ns = take n (randoms g)
show (ns :: [Int])
B
genNRandom :: Int -> [Int]
genNRandom n = do
g <- getStdGen
take n (randoms g)
@はコンパイル通るけどAとBがダメなのはなんでなんだぜ?
で、
URLリンク(www.sampou.org)
読んでたらなんとなく分かった気がしたんだけど要するにIOモナドは1方向モナドで、値が取り出せないし、
IOモナド使ってる関数は返り値の型が絶対IO()とかになるから参照透明じゃないのが他の関数まで波及しないよって意味なのか?
じゃMaybeとかStateとかは使っても参照透明なままなのか?
47:デフォルトの名無しさん
07/11/06 20:57:35
2は型がInt -> IO Stringで、最後をreturn(show(ns::[Int]))にせないかん。
3は型がInt -> IO [Int] で、最後をreturn(take n (randoms g))にせないかん。
48:デフォルトの名無しさん
07/11/06 22:22:38
それ>>34でも教えてもらったな… 俺わかってないな…
(・´ω`・)ぅーん
49:デフォルトの名無しさん
07/11/06 22:35:47
>>46
IOモナドを使った関数も参照透明だよ。
個人的には、IOモナドを「副作用を閉じ込める」と表現したり、
値を取り出せるかどうかを云々しても混乱するだけだと思う。
むしろ、IO aとaは全然別のものであるという認識を推奨。
実際、IO aの中にa型の値など入っていない。
この辺読んでみたらどうだろう。
URLリンク(www.ice.nuie.nagoya-u.ac.jp)
50:デフォルトの名無しさん
07/11/06 23:09:33
letのところは無視してdo構文の各行を最終的な型だけで見てやったら
それぞれこんな感じになって、
1. do {r <- IO r; IO ()}
2. do {r <- IO r; String}
3. do {r <- IO r; [Int]}
これを >>= を使った形にしたらこんな感じ。
1. IO r >>= (r -> IO ())
2. IO r >>= (r -> String)
3. IO r >>= (r -> [Int])
(>>=) :: m a -> (a -> m b) -> m bだから
>>=の前後は m a >>= (a -> m b) って状態になってないといけない。
1はちゃんとそれを満たしてるからOKだけど、
2はString = [Char] = [] Charで、IO ≠ []なのでNG。
3も同様にNG。
51:デフォルトの名無しさん
07/11/06 23:39:33
>>49
読んだ 少し分かったような分からないような…?
YOUはIOモナドを使った関数も参照透明だよって言ってるけど
標準入力読んだときとか乱数生成したときとか同じ引数あげても同じ値が返ってくるとは
限らないじゃん それって困るんじゃないの? って思うの
>>50
>>49の説明と合わせたらちょっと分かったかも
そーいえばリストもモナドなんだったっけ
例示してくれた1.2.3.の例はHaskellとして正しい文法なん?
言いたい意味はわかるけどそういう書き方があるの?
前スレ952が教えてくれたサイトやら見てみたけどわかんない…
52:デフォルトの名無しさん
07/11/07 00:05:04
>>51
randomRIO :: (Int, Int) -> IO Int
というのを考えてみる。これは要するに与えられた範囲の乱数を生成する関数な訳だけど、
厳密に考えると、これは動作を返す関数で、同じ引数で呼ばれたら常に同じ動作を返す。
例えば、(0, 3)を与えて呼び出すと、常に「0以上3以下の乱数を生成する」という動作を返す。
この「動作」を実行した結果はもちろん毎回違うけど、それをHaskellプログラムが
受け取ることはないので、参照透過性には影響ない。
(この動作の結果を受け取って別のことをする、より大きな動作を作ることはできるけど)
これは別に言葉遊びじゃなくて、実際、randomRIO (0, 3)が複数回出てくる巨大な式
f x = ... randomRIO (0, 3) >> ...... fmap (1-) $ randromRIO (0, 3) ...
があったとして、これを機械的に一つにまとめて
f x = let z = randomRIO (0, 3) in ... z >> ...... fmap (1-) $ z ...
としても意味が変わらないことが保証される。これが参照透過性。
53:デフォルトの名無しさん
07/11/07 00:06:11
文法として正しいわけねぇじゃん。あくまで説明用。
54:デフォルトの名無しさん
07/11/07 00:25:41
>>52
アクションやら動作うんぬんとかいうことかー
変数に束縛して使ったときに動作が実行されて〜〜みたいな?
main = do
rnd <- randomRIO(0,3)
putStr $ show (rnd :: Int)
とかすると束縛したときはアクションですけどshowに渡るときにはいつの間にか数字ですよみたいなごまかし方(?)なのか?
ていうかghcでコンパイルしたあと実行すると処理が帰ってこないんだけどghciでmain呼ぶとちゃんと表示される罠 意味わかんね
>>53
だってわかんなかったんだもん いぢわるー
55:デフォルトの名無しさん
07/11/07 00:44:46
>>54
do記法で
rnd <- randomRIO (0, 3)
と書くと、rndが束縛されるのは数値Intであって動作IO Intじゃない。
矢印の右辺と左辺は別物。というかこの行だけ取り出すのは無意味。
do式全体で、「randomRIO (0, 3)を実行し、その結果がrndならばputStr $ show rndを実行するという動作」と読む。
慣れるまではdo記法をほどいて
randomRIO (0, 3) >>= (\rnd -> putStr $ show rnd)
に戻して考えるようにした方が分かりやすいかもしれない。
俺の手元ではコンパイルしたのもちゃんと動いたよ。
56:デフォルトの名無しさん
07/11/07 00:57:31
>>55
( ´3`)<よくわかんなーい
乱数を生成する動作を返す関数があって、その動作が実行されてモノホンの数値になる瞬間がある気がするんだけど気のせいなのか?
ちなみに
The Glorious Glasgow Haskell Compilation System, version 6.6.1
ghc test.hs --makeでコンパイルしてtest.exe実行→処理帰ってこない
57:デフォルトの名無しさん
07/11/07 01:41:54
>>56
いや、Haskellプログラムは最初から最後まで動作をこねくりまわしてるだけで、
いつ実行されるかという話はあまり関係ない。
「ジャガイモの皮を剥く」というレシピと「茹でる」というレシピから
「ジャガイモの皮を剥いて茹でる」というレシピを合成する、という次元のことをやってる。
この作業をするとき、実際にいつレシピに基づいて料理が行われるかを気にする必要はない。
実際には、プログラムを起動すると即座にmainが「実行」されはじめて、
それに必要な分だけ「評価」が起こる訳だけど。
58:デフォルトの名無しさん
07/11/07 07:08:36
なるほどー
レシピは完成品を作っちゃくれないってか
59:デフォルトの名無しさん
07/11/07 11:47:38
こねくり回し方を想像できない人は素人
60:デフォルトの名無しさん
07/11/07 19:57:03
Haskellの素人なのか園論の素人なのか数学の素人なのかなんの素人なのかさえ分からない俺はキングオブ素人
今日もまたわからないことがいっぱいでした…
61:デフォルトの名無しさん
07/11/07 20:16:10
この場合は処理系の素人
62:デフォルトの名無しさん
07/11/07 20:17:56
ちなみに、園論ではなく圏論(けんろん:category theory)
63:デフォルトの名無しさん
07/11/07 20:25:13
その・さとしさんが提案
64:デフォルトの名無しさん
07/11/07 20:31:53
>>63
誰?
65:デフォルトの名無しさん
07/11/07 20:50:21
>>64
園諭を提案した人
66:デフォルトの名無しさん
07/11/08 23:04:52
ハスケルルでメシ食ってる人いんの?
67:デフォルトの名無しさん
07/11/09 00:37:52
本業でやってる人はおそらくいない。(研究者除く)
68:デフォルトの名無しさん
07/11/09 03:04:27
カリーでメシ食ってるのならいる
69:デフォルトの名無しさん
07/11/09 07:50:26
GHC 6.8.1でコンパイルし直しただけで本当にプログラムが二割高速化してワラタ
それから-O2をつけた場合のコンパイル速度が六倍になったけど、これは-fasmがデフォになったおかげだな
70:デフォルトの名無しさん
07/11/09 21:01:59
お前ら
コマンドライン引数から複数のテキストファイル名を取得してその中身を標準出力に出力するプログラム書いてみてくれ
IO [String]が…[]外れねぇよチクショウorz
71:デフォルトの名無しさん
07/11/09 21:22:15
import System.Environment
main = do
args <- getArgs
mapM_ dump args
where
dump file = do
content <- readFile file
putStr content
こんなの?
72:デフォルトの名無しさん
07/11/09 21:30:54
そんなの…
俺とてつもなく頭悪い気がしてきた('A`)
73:デフォルトの名無しさん
07/11/09 23:45:24
>>71 のを短く書けばこんな感じ
import System.Environment
main = getArgs >>= mapM_ ((putStr =<<) . readFile)
74:デフォルトの名無しさん
07/11/10 01:57:22
>>71のをArrowで書けばこんな感じ
mapA :: ArrowChoice a => a b c -> a [b] [c]
mapA f = arr listcase >>>
arr (const []) ||| (f *** mapA f >>> arr (uncurry (:)))
where
listcase [] = Left ()
listcase (x:xs) = Right (x,xs)
main :: IO ()
main = runKleisli (Kleisli (const getArgs) >>> mapA (Kleisli readFile) >>> arr concat >>> Kleisli putStr) ()
-- mapAみたいに便利な関数は早く標準ライブラリに入れてほしい
75:デフォルトの名無しさん
07/11/10 12:58:22
>>74
モナドと組み合わせると恐ろしく単純にかけるようになる
main = getArgs >>= mapM_ (readFile >>> putStr)
76:デフォルトの名無しさん
07/11/10 13:01:01
>>75
Kleisliをつけたり外したりがいらないか?
77:デフォルトの名無しさん
07/11/10 13:27:49
まあ、>>>の正体は f >>> g = g . f だからなぁ。
78:デフォルトの名無しさん
07/11/10 17:30:40
arrowベースのIOってないもんかね
79:デフォルトの名無しさん
07/11/10 22:17:13
Haskellで開発会社をやりたいという夢を持つ自分はタダのバカですか?
80:デフォルトの名無しさん
07/11/10 22:20:08
実行しようとしない点でバカです。
81:デフォルトの名無しさん
07/11/10 22:25:52
>>80
何こいつスゴいかっこいいんだけど
82:デフォルトの名無しさん
07/11/10 22:26:01
>>79
保守できないに100ルピー
83:デフォルトの名無しさん
07/11/11 11:03:25
部下がpoint-free styleで1000行くらいのバグ入りコードを提出
という悪夢を見てしまった
84:デフォルトの名無しさん
07/11/11 13:55:48
>>83
現在適当な粒度の関数に分解する鶴を開発中です
85:デフォルトの名無しさん
07/11/11 13:57:05
>>79
無責任名誉会長は俺ね。
86:デフォルトの名無しさん
07/11/11 19:07:03
>>70
素直にλを残した方が分かりやすいわな。
main = getArgs >>= mapM_ (\a -> readFile a >>= putStr)
87:79
07/11/11 19:39:30
しかし、Haskellなどの関数型言語専門会社っていうのは憧れます。
自分はまだ初心者でチュートリアル勉強している段階ですけど、この世界が
広がったら素晴らしいなぁと本気で思ってますよ。
私の現在の妄想は、最近メジャーになってきたWebサービスの関数型版。
住所 -> GoogleMapAPI -> 天気予報 -> 天気マーク付き地図
88:デフォルトの名無しさん
07/11/11 19:53:47
バカっつーか、中学生臭い
89:デフォルトの名無しさん
07/11/11 19:59:51
>>87
それは俗に言う「マッシュアップ」というやつではないか?
関数型言語と関係なくそこら辺の奴でも作れるぞ。
90:デフォルトの名無しさん
07/11/11 20:11:17
そうだな
ただのマッシュアップだな
masuidriveのブログとか見るといいような気がするよ
そして
>>71-77,86の諸氏よありがとう
よく理解できないから明日色々試してみるわ…
Haskell挫折しそう… 書いてて楽なのは分かるんだけど…分かるんだけど…
91:79
07/11/12 07:08:04
いや、マッシュアップを関数型でやってるのを見たいんだけど。
もうあるの?
92:デフォルトの名無しさん
07/11/12 11:01:32
プロシンあたりで誰か発表してるかも〜
とか無責任に書いてみる
93:デフォルトの名無しさん
07/11/12 16:47:36
>>86
そこまで来たらやっぱりこう書きたくなる
main = getArgs >>= mapM_ ((>>= putStr) . readFile)
94:デフォルトの名無しさん
07/11/12 16:56:09
好みが分かれるもんだな
俺はラムダ抽象が嫌いなのでwhere節を使う
95:デフォルトの名無しさん
07/11/12 19:48:05
>>94
お前の好みはhaskellには不向きだな。
96:デフォルトの名無しさん
07/11/12 20:14:14
そうか?俺がHaskell好きな理由の一つがこれなんだが
where節みたいにローカル変数を使った後に定義できる言語は他にはCleanくらいしか知らない
それに嫌いって言っても使うことは結構ある。>>86みたいな例なら迷わずwhereを使うってだけで
97:デフォルトの名無しさん
07/11/12 20:58:37
>>96
関数の内部で関数を定義できる言語はいくらでもある。rubyとか。
98:デフォルトの名無しさん
07/11/12 21:06:16
それは知ってる。でも関数を「使った後に定義」はできんだろ
99:デフォルトの名無しさん
07/11/12 21:18:00
使った後に定義ってどういう意味?
100:デフォルトの名無しさん
07/11/12 21:19:56
>>99
ソースコード上で定義が参照よりも後に現れること
f x = g -- ここでgを使う
where
g = 2 -- ここでgを定義
101:デフォルトの名無しさん
07/11/12 21:26:38
int main(char args[][]){
owata();
}
void owata(){
writefln("\(^o^)/");
}
102:デフォルトの名無しさん
07/11/12 21:27:46
使った後に定義してるわけじゃないけど、遅延評価が便利って言いたいわけね。
103:デフォルトの名無しさん
07/11/12 21:28:18
>>101
>>98はローカル関数の話な、誤解させてすまん
104:デフォルトの名無しさん
07/11/12 21:30:21
>>102
なんというエスパー
105:96
07/11/12 21:32:27
>>102
遅延評価はあまり関係ないと思う。あくまでコード上に現れる順序の問題
極端な話、正格な言語で
f x = y where y = 2
が
f x = let y = 2 in y -- このletは正格
の構文糖なだけでも俺には十分
106:デフォルトの名無しさん
07/11/12 22:26:37
Lisp 系だったらその手の構文糖は作り放題だけどね。
実際、昔 ELisp でそんな感じの macro 自作して使ってたし。
107:デフォルトの名無しさん
07/11/12 23:36:21
はいはい自慢はいいですよ
108:デフォルトの名無しさん
07/11/13 00:18:43
興ざめするから自慢とか言わないでくれよ…
109:デフォルトの名無しさん
07/11/13 12:48:47
なら、自己満
110:デフォルトの名無しさん
07/11/13 19:37:02
初心者です。
今、いろんなテキスト漁って勉強中ですが、モナドのところ見てて不思議に思いました。
これって、早晩知らなくてもHaskellが書けるようになったりするんじゃないのでしょうか。
今はまだ途上なので、透過参照を維持できるように云々と理論的な面が表に強く出て
ますけど、近いうちに標準のAPIからは隠蔽されていくということはないですか?
111:デフォルトの名無しさん
07/11/13 19:37:31
それなら良いわ
112:デフォルトの名無しさん
07/11/13 19:42:46
>>110
>>73をモナドを使わずに書いてください
113:デフォルトの名無しさん
07/11/13 19:57:53
>>110
歴史的にはどうか知らんが、モナドは参照透過性のために仕方なくあるわけじゃなくて、
道具として積極的に使われてる。だからHaskellでモナドが使えなくなることは考えられない。
モナドを知らなくてもIOを書けると良い、という話なら、現状でもできると思う。
114:デフォルトの名無しさん
07/11/13 20:22:01
質問です
>>93をみてこんなの↓つくってみたんだけど、
main :: IO ()
main = getArgs >>= mapM_ ((>>= putStrLn.conv).readFile) >> getCPUTime >>= print
where
conv :: String -> String
conv = unlines.(map ((map toLower).(filter (/= '\"')))).lines
最初に与えたファイルパスのぶんが読まれないっぽいんよ
c:\Users\aiueo> main < c:\a.txt c:\b.txt
と入力すると、b.txtの中身とCPUTimeだけが表示されるんだよね
エロい人なぜだか教えてください
115:デフォルトの名無しさん
07/11/13 20:27:40
>>110
モナドを使わないと、実用的なHaskellのプログラムは書けない。
モナドの理論的な側面を詳しく知らなくとも、モナドを使うことはできる。
結論:
モナドの理論的な側面は今は無視して、モナドを使ってHaskellのプログラムを書けばよろし。
理論的なことは後から少しずつ覚えていけばよろし。
116:デフォルトの名無しさん
07/11/13 20:29:38
>>114
「<」これはリダイレクション
117:デフォルトの名無しさん
07/11/13 20:30:00
>>114
だってそれa.txtは標準入力に与えられてるもんよ
c:\Users\aiueo> main c:\a.txt c:\b.txt こーやれ
118:デフォルトの名無しさん
07/11/13 20:39:55
>>116,117
ありがとう!
119:デフォルトの名無しさん
07/11/13 21:09:22
ちょっとお前ら聞きたいんだけどさ
なんで>>86みたく書くんだ?
main = mapM_ (\a -> putStr =<< readFile a) =<< getArgs
でよくね?モナド使わないときとモナド使うときで読む方向違うのってやりにくくね?
なんか理由あんの?おせーておせーて
120:デフォルトの名無しさん
07/11/13 21:14:55
俺も時々下から順に実行されるdoが欲しくなる
121:デフォルトの名無しさん
07/11/13 21:25:47
>>113>>115
ありがとうございます。"モナド"という言い方がよくありませんでした。Maybeとか
リストのモナドは仰るように積極的に使われていると自分も思いました。
ただ、IOモナドがよく分からんのですね。特にIORefとか。この手のものは、単に
透過参照性を維持するためのテクニックと見えてしまいます。
122:デフォルトの名無しさん
07/11/13 21:34:19
>>119
だったら>>75が自然に見えてくるだろう
123:デフォルトの名無しさん
07/11/13 21:38:12
でも、>>75はコンパイル通らんぞw
124:デフォルトの名無しさん
07/11/13 21:41:42
>>123
処理系とそのバージョンは?
Control.Arrowをインポートしたかどうか。
125:デフォルトの名無しさん
07/11/13 21:48:31
いや、明らかに型が合わんだろ…
readFile :: String -> IO String
putStr :: String -> IO String
(>>>) :: (Arrow a) => a b c -> a c d -> a b d
instance Arrow (->)
126:125
07/11/13 21:49:19
間違えた
putStr :: String -> IO ()
ね
127:デフォルトの名無しさん
07/11/13 21:52:41
>>121
参照透過性を壊さないでIOを実現するに当たって、現状よりマシなインタフェースがあるってこと?
128:デフォルトの名無しさん
07/11/13 23:40:51
>>124
無理やりコンパイル通せばこうなるぞ。
main = getArgs >>= mapM_ (readFile >>> (>>= putStr))
Kleisli使うのは俺はパスw
129:デフォルトの名無しさん
07/11/14 01:19:08
2次関数が苦手だったから関数言語なんて滅びてほしい
130:デフォルトの名無しさん
07/11/14 01:31:50
釣られないぞ
131:デフォルトの名無しさん
07/11/14 05:55:26
a -> IO b は Kleisli IO a b と同じ構造をもつんだけど、Haskell のnewtypeが違う型として扱ってしまうために、>>75 のように楽天的にはいかないんですな
だからといって 型シノニムで定義できるわけでもないので、しょうがないんだけど
132:デフォルトの名無しさん
07/11/14 14:53:09
これでどうよ!
main = getArgs >>= mapM_ (readFile >=> putStr)
133:デフォルトの名無しさん
07/11/14 15:38:28
入門HaskellのP104にあるインスタンス宣言について質問なんですが
instance (Eq a) => Eq (Maybe a) where
の(Eq a) => はどうして必要なんでしょうか?
134:デフォルトの名無しさん
07/11/14 16:05:38
>>133
中身が比較できないとMaybeも比較できないじゃん
具体的には、
instance (Eq a) => Eq (Maybe a) where
Nothing == Nothing = True
Just a == Just b = a == b -- このa==bが意味を持つことを保証しないといけない
_ == _ = False
135:デフォルトの名無しさん
07/11/14 16:39:52
>>134
Maybe aとaを同一視してましたorz
わかりやすい説明ありがとうございました。
136:デフォルトの名無しさん
07/11/14 19:13:05
do cs <- getContents
hoge <- getContents
putStr hoge
↑のような式を>>=を使って書き直した場合、どのような式になるのでしょうか?
137:デフォルトの名無しさん
07/11/14 19:17:43
>>136
getContents >>= \cs ->
getContents >>= putStr
138:136
07/11/14 20:05:49
すいません
do cs <- getContents
hoge <- getContents
putStr hoge
じゃなくて
do hoge <- getContents
cs <- getContents
putStr hoge
の間違いでしたorz
139:デフォルトの名無しさん
07/11/14 21:17:45
>>138
getContents >>= \hoge ->
getContents >>= \cs ->
putStr hoge
このケースでは(>>=)を使う旨みはないね。
140:デフォルトの名無しさん
07/11/14 22:11:24
この場合、
A. getContentsを2回やってからputStr
B. putStr hogeをやるために1個目のgetContentsをやって2個目のは保留
のどっちの動作になるんだっけ。
遅延評価的にはBだよね?
141:デフォルトの名無しさん
07/11/14 22:18:38
>>140
IO動作は上から順に(厳密には>>=の左辺から右辺へ)実行される
getContentsの動作は特殊で、読み込み自体は文字列が必要とされるまで遅延される
だから、順序としては、
1. 1個目のgetContentsが実行され、ハンドルがセミクローズされる。遅延読みのため即座にリターン
2. 2個目のgetContentsが実行され、ハンドルがセミクローズ状態なので例外発生
で、putStrは実行されない
142:デフォルトの名無しさん
07/11/14 22:28:25
そういう風な動作になるのか。ちょっと勘違いしてた。Thanks
143:デフォルトの名無しさん
07/11/14 22:55:19
ここってクロスコンパイルネタはスレ違いですか?
144:デフォルトの名無しさん
07/11/14 23:11:31
ここしかないだろw
145:デフォルトの名無しさん
07/11/14 23:31:03
クロスコンパイルの場合、GHC(6.4.xや6.6.x)のMakefileって修正なしで通りますか?
依存関係を無視したり、更新情報を無視したり、
無いファイルを参照したり、必要なターゲットを生成しなかったりと
明らかに修正しなければならない部分が多々あるようですが
146:143=145
07/11/15 00:01:32
私の環境で6.6.1をクロスコンパイルする場合、少なくとも
ホスト、ターゲットで共通
・distrib以下のファイルに実行許可がされていない
・configureでgmpのヘッダ、ライブラリ位置を指定しても途中から無視する
・makeをやり直した場合、すでに生成したファイルで且つ更新の必要がないものでも再ビルドする場合がある
ホストでは、
・libraries/Cabal/cabal-setup/CabalSetup.hcを生成してくれない
・かといってターゲットとして生成したファイルだとundefined referenceが発生するので-keep-hc-filesを指定してCabalSetup.oをリコンパイルしなければならない
・hc-file-bundleする際、libraries/haskell-src/Language/Haskell/Parser.hsという存在しないファイルをアーカイブしようとする
(現在ビルド中ですので途中までしかわかっておりませんが)ターゲットでは
・compiler/primop*.hs-inclが空ファイルで生成される
・compiler/stage1にインタフェースファイルが生成されないためpreludeのビルドに失敗する
等が確認できました
i386-unknown-openbsd → arm-unknown-openbsdという特殊な環境ということもありますが、
普通の環境ではすんなりクロスコンパイルできるのか疑問に思えました
147:143
07/11/15 00:07:35
ちなみにOpenBSD-makeではなくGNU-makeを使用しています
148:デフォルトの名無しさん
07/11/15 01:19:56
Ubuntu上のemacs22+ghc6-6.1でHaskellのプログラムを色々試しているんですが
C-c, C-lを実行するとよくEmacsが固まってしまって何の入力も受け付けなく
なってしまいます。そのたびにkill -KILLをしているんですが
同じような症状の人はいないでしょうか?
149:デフォルトの名無しさん
07/11/15 01:36:11
debianですが、固まりませんね。
150:デフォルトの名無しさん
07/11/15 03:01:07
IORefについて質問です。
do ioref <- newIORef 0
modifyIORef ioref (+1)
readIORef ioref >>= print
という式の中でmodifyIORef ioref (+1)がiorefの値を変更している仕組みが
どうしてもわかりません。予想としては
・modifyIORefを使うと引数の値を変更できると言語の根っこの部分で決められている
という事かなと思っているんですが、この考えでいいんでしょうか?
151:デフォルトの名無しさん
07/11/15 07:23:12
>>150
C言語の例でよければ
*ioref=*ioref+1;
で変更されるのは*iorefであってiorefではない。
Perlなら
$$ioref=$$ioref+1;
といった具合で。
Cで詳細に書いてみる。
void modifyIORef(int * ioref,int (*fn)(int)){
*ioref=fn(*ioref);
}
int add1(int arg){
return arg+1;
}
int readIORef(int * ioref){
return *ioref;
}
int main(){
int * ioref;
ioref=newIORef(0);
modifyIORef(&add1);
printf("%d\n",readIORef(ioref));
return 0;
}
まあ(>>=)の部分(doで省略される部分とか)までより近く書くともっと長くなりますが。
それ以前にかけるかどうかちょっと自信ないけど。
*iorefは変更されてもiorefは1回の初期化時の変更のみということで。
152:150
07/11/15 08:04:34
>>151
つまりHaskellは、定数だけでなく、変更される変数の値を保存しておくための(つまり再代入可能な)
場所も用意しているということなんでしょうか?
153:デフォルトの名無しさん
07/11/15 10:27:06
>>152
実装上はその通り。GHCにはヒープ上に変更可能オブジェクトを置くための機構があるし、
多分Hugsも似たようなもの。
一方で、言語について「Haskellは〜用意している」という言い方をするのは誤解がある気がする。
実際、>>151の言うように、IORefを使っても(Haskellの普通の)変数の値が変更されることはないし、
言語の根幹に変更を迫るような拡張じゃない。
扱える型を限定すれば、自分で(ファイル入出力を使ったりして)IORefみたいなものを書くこともできる。
154:150
07/11/15 13:37:19
>>153
よくわかりました。ありがとうございます。
今入門HaskellとふつうのHaskellの二冊を読みながら色々試しているんですが
もうちょっと詳しい説明が欲しいなと思うことがよくあります。
そこでプログラミングPerlのような
・どのようにHaskellでプログラミングするか
・Haskellはどういう理由でこういう風になっているのか
を解説した本が欲しいのですが、テンプレに載っている洋書で↑の内容に
合っている本はないでしょうか?
155:143
07/11/15 13:54:41
Makefileを読む時間的余裕が無かったのでとりあえず
find compiler/stage1 -name ¥*.o -exec rm {} ¥;して
make -C compiler boot stage=1 && make -C compiler stage=1したら
ビルド&インストールに成功したようです
後でパッケージを作って本インストールするつもりです
日本語のクロスコンパイルのドキュメントが少ないので
作業過程を簡単に書かせていただきたいと思います
(需要は無いでしょうけど)
うざったいと思われる方は「クロスコンパイル」をNGワードにしてください
156:デフォルトの名無しさん
07/11/15 13:56:24
>>154
・どのようにHaskellでプログラミングするか
→『Haskell: The Craft of Functional Programming』
・Haskellはどういう理由でこういう風になっているのか
→『Introduction to Functional Programming Using Haskell』
かなあ。両方とも良い本だと思う。まだ全部読み切ってないけど。
157:150
07/11/15 21:41:29
>>156
その二冊ですね。お金に余裕ができたら買ってみます。
話は変わるのですがHaskellのガベージコレクションは他の言語(java,ruby...)
と比べて動作する機会がほとんどないと思うんですがどうでしょうか。
変数の宣言時にしか値を入れられなくて、グローバル変数とスタック上に
載せられるローカル変数でほとんど全てが賄えるなら
どこからも参照されていないデータ(ガベージコレクタの対象になるデータ)
ができるなんてことはまずないと思うんですが・・・
158:デフォルトの名無しさん
07/11/15 22:41:43
>>157
そんなことはない。遅延評価のために何でもかんでもヒープに割り当てないといけないので、
Haskellは平均的な言語よりずっと多くゴミを出す。
GHCでコンパイルしたプログラムなら、+RTS -Sstderrオプションをつけて実行すれば
GCがどれくらい動いたかが分かる。
適当なプログラムで試してみたけど、約3秒の実行時間中にヒープから700MBほど確保し、
そのうち約9割は第0世代のGCで即座に捨てられてた。
159:デフォルトの名無しさん
07/11/15 22:45:57
具体的に数字出されるとびっくりするなw
160:デフォルトの名無しさん
07/11/15 22:47:23
俺もびっくりしたwww
161:デフォルトの名無しさん
07/11/15 23:07:27
700MB?
700mBの間違いじゃないのか
162:デフォルトの名無しさん
07/11/15 23:15:22
700*2^20 bytesね
741,834,476 bytes allocated in the heap
108,671,480 bytes copied during GC (scavenged)
2,030,404 bytes copied during GC (not scavenged)
13,955,072 bytes maximum residency (11 sample(s))
1415 collections in generation 0 ( 0.55s)
11 collections in generation 1 ( 0.43s)
32 Mb total memory in use
163:デフォルトの名無しさん
07/11/16 01:10:19
やさしい Haskell 入門を今見ているんですが
4.4 遅延パターン
URLリンク(www.sampou.org)
での最初の例
reqs = client init resps
resps = server reqs
client init (resp:resps) = init : client (next resp) resps
server (req:reqs) = process req : server reqs
がどういう意味なのかさっぱりわかりませんorz
どうして↑がだめで
client init resps = init : client (next (head resps)) (tail resps)
だとOKなんでしょうか?
164:デフォルトの名無しさん
07/11/16 02:19:04
>>162
これって瞬間最大メモリ使用量が700MBってこと?
165:デフォルトの名無しさん
07/11/16 02:50:58
うさのパソコンはメモリ256MB!
166:デフォルトの名無しさん
07/11/16 02:52:24
アプリ側がメモリ確保に成功しても、
OS側で本当に実メモリを消費したとは限らないから
調べないと分からないか。
167:デフォルトの名無しさん
07/11/16 03:27:46
>>164
アロケートされたメモリの数が700MBってことなのだが、実際はgeneration 0に割り当てられた少ないメモリが使いまわされているだけだから、メモリの使用量自体は少ないはず。
168:デフォルトの名無しさん
07/11/16 07:15:29
>>164
OSから確保したのが32MB
実際のヒープオブジェクトの総量が瞬間最大で13,955,072 bytes
コピーGCだからOSから確保した領域の半分以下しか貯められない
次ページ最新レス表示スレッドの検索類似スレ一覧話題のニュースおまかせリスト▼オプションを表示暇つぶし2ch
5198日前に更新/201 KB
担当:undef