関数型プログラミング ..
[2ch|▼Menu]
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から確保した領域の半分以下しか貯められない

169:デフォルトの名無しさん
07/11/16 17:49:52
StateモナドでunsafeInterleaveIO的な関数って書けますか?
do
xs <- interleaveState $ sequence $ replicate 3 get
sequence $ map set xs

で get set get set get setの順になるようなやつ

170:デフォルトの名無しさん
07/11/16 18:08:04
unsafe禁止令

171:デフォルトの名無しさん
07/11/16 18:26:23
xs <- sequence $ replicate 3 $ interleaveState get
の間違いか?
どっちにしても無理だろ

172:デフォルトの名無しさん
07/11/16 18:36:40
>>171
すいません、間違いでした
無理orz

173:デフォルトの名無しさん
07/11/16 22:22:17
モナドと代数的データ型に的を絞って詳しく扱ってるテキストはないでしょうか


174:デフォルトの名無しさん
07/11/17 03:16:48
foo >>= bar
としたときに実際に>>=がどのインスタンスに定義されている>>=の処理を行うのか、
というのはどうやって決まるんでしょうか?

175:デフォルトの名無しさん
07/11/17 07:11:03
>>174
型推論。fooの型とbarの型とその式の使われ方が勘案される。

176:デフォルトの名無しさん
07/11/17 11:11:46
>>175
それはコンパイル時と実行時のどちらでされるものなんでしょうか?

177:デフォルトの名無しさん
07/11/17 11:43:58
>>176
実行時

178:デフォルトの名無しさん
07/11/17 11:57:24
・型推論自体はコンパイル時。
・ただし、型クラスのディスパッチは実行時まで遅延される。
・ただし、どのインスタンスについてのコードを生成すれば良いか静的に決まる場合は、
最適化の一環としてディスパッチを省略する。

こんな感じか。

179:174
07/11/17 12:49:35
>>177、178
なるほど、静的に型をチェックしつつ、動作は動的に決まるんですね。

ところで
数学パズル ものまね鳥をまねる―愉快なパズルと結合子論理の夢の鳥物語
URLリンク(www.amazon.co.jp)
E3%82%92%E3%81%BE%E3%81%AD%E3%82%8B%E2%80%95%E6%84%89%E5%BF%AB%E3%81%AA%E3%83%91%E3%82%BA%E3%83%AB%E3%81%A8%E7%B5%
90%E5%90%88%E5%AD%90%E8%AB%96%E7%90%86%E3%81%AE%E5%A4%A2%E3%81%AE%E9%B3%A5%E7%89%A9%E8%AA%9E-%E3%83%AC%E3%82%A4%E3%
83%A2%E3%83%B3%E3%83%89-%E3%82%B9%E3%83%9E%E3%83%AA%E3%83%A4%E3%83%B3/dp/4627019017/ref=sr_1_9?ie=UTF8&s=books&qid=1195271100&sr=1-9
この本を読んだことがある人いますか?関数プログラミングの土台の考え方がわかる本らしいんですが。



180:デフォルトの名無しさん
07/11/17 13:28:59
>>179
途中まで読んだだけだけどコンビネータの話。
S,K,I とか。Yコンビネータも出てきたかは覚えてない。

181:デフォルトの名無しさん
07/11/17 16:07:56
a 1 = "hoge"
a 2 = 2
のような引数によって異なる型の値を返すことはOKなんでしょうか?


182:デフォルトの名無しさん
07/11/17 16:22:37
>>181
template haskell

183:デフォルトの名無しさん
07/11/17 16:25:26
>>181
ダメ

184:デフォルトの名無しさん
07/11/17 16:30:24
2種類の型のどちらかを返したい場合はEitherを使う。
a :: Int -> Either String Int
a 1 = Left "hoge"
a 2 = Right 2

185:182
07/11/17 16:51:52
template haskellじゃなくてgeneric haskellだった・・

186:デフォルトの名無しさん
07/11/17 22:16:41
>>163
今日Haskell始めたばかりのド素人なんだけど、
ones = addlist 1 onesでも、

addlist init xs = init : head xs : tail xs -- [1,1,1,1,1,1,1,1,1,1]
addlist init xs = init : xs         -- [1,1,1,1,1,1,1,1,1,1]
addlist init ~(x:xs) = init : x : xs     -- [1,1,1,1,1,1,1,1,1,1]
addlist init (x:xs) = init : x : xs       -- C stack overflow

ってなる。要するに(x:xs)が含まれる部分が先に解釈されるとマズいってことじゃないかな。
単体でのxsはパターンはパターンでも手続き型言語での仮引数と同じ程度の意味しかもたないパターンだから暗黙的に遅延される。
head xsやtail xsも関数だからxsが未確定なら遅延される。
でも(x:xs)というパターンは未確定でも遅延しないでxとxsを照合しようとする。
結果的にinitに値がセットされる前にx:xsを延々と調べ続ける。それではマズいので、(x:xs)を遅延パターンにする、ってことじゃないかな。

187:デフォルトの名無しさん
07/11/17 23:24:01
>>163
明日からHaskell始めるつもりのド素人なんだけど、
関数の仮引数xがconstructor pattern(たとえばy:ys)の場合、
それはcase x of y:ys -> ...という形に変換される。
で、caseの条件式はWHNFまで評価されてしまうので、
遅延させたい時には使えない。

188:186
07/11/17 23:31:58
>>188
あ、なるほどそういうことなのか。
ありがとう。無理して答えた価値あったわ。

189:163
07/11/17 23:59:14
なんとなく理解できました。ありがとうございます。
Haskellの考え方に慣れるまでまだ時間がかかりそうですorz

190:デフォルトの名無しさん
07/11/18 00:28:05
sequence :: Monad m => [m a] -> m [a]
sequence = foldr mcons (return [])
       where mcons p q = p >>= \x -> q >>= \y -> return (x:y)

↑のsequenceの定義を見るとfoldrが使われているんですが、それだと
sequence [putStr "foo", putStr "bar"] の場合リストの後ろの方、
つまりputStr "bar"の方が先に評価されるのに、実際には
fooの方が先に出力されてしまいます。どうして後ろからではなく、先頭から
評価されるんでしょうか?

191:デフォルトの名無しさん
07/11/18 00:55:14
式の評価順とIOモナドの実行順は別物。

192:デフォルトの名無しさん
07/11/18 01:04:47
sequence [A, B, C]
= A `mcons` (B `mcons` (C `mcons` (return [])))
= A >>= (\x -> (B `mcons` (C `mcons` (return []))) >>= \y -> return (x:y))

よってA, B, Cの順にエフェクトが出る。


193:デフォルトの名無しさん
07/11/18 01:17:35
>>178
Haskell今日始めた人なんだけど
その最適化の一環としてディスパッチが省略された場合ってのは
C++でいうとtemplateによってコード生成された状態と考えていいんですかね

194:デフォルトの名無しさん
07/11/18 02:12:23
main = putStr "hoge" >>= \x -> putStr "foo" >>= \y -> return x
main = putStr "hoge" >>= \x -> putStr "foo" >>= \y -> return y
main = putStr "hoge" >>= \x -> putStr "foo" >>= \y -> return "bar"

↑のように最後にreturnさえすればエラーにならずhogefooと出力されるということは、
IOモナドはMaybeモナドやListモナドと違って、最後に何を返すかではなく、
動作をどういう順に行うのかを決めるための仕組みだと考えればいいんでしょうか?


195:デフォルトの名無しさん
07/11/18 08:09:29
>>193
そんな感じ。

>>194
何を返すかによってmainの型が違う。
上の二例ではIO ()で、最後の例だとIO String。
両方コンパイルが通るのは、mainの型はIO αという形なら何でもよく、
生成されたα型の値は無視されることになってるから。

196:デフォルトの名無しさん
07/11/18 13:45:25
>>178
実行時にならないとどのインスタンスのコードが実行されるか
静的に決まらない場合ってどんな場合??

197:デフォルトの名無しさん
07/11/18 13:51:59
>>196
クラスのインスタンス一般に対して書かれた関数は全部そう。例えば、
double :: (Num a) => a -> a
double x = x + x
こんな関数を定義したら、これをコンパイルする時点ではどの(+)を使うべきか決まらない。

198:193
07/11/18 13:56:54
>>197
その関数doubleに対して具体的に値を入れたときに
コード生成される(静的に生成?)んじゃないんですかね?

頭がC++脳なのでtemplateのことばっかり頭に浮かんでしまうんですがね…

199:デフォルトの名無しさん
07/11/18 14:08:31
>>198
少なくともGHCやJHCならdoubleが定義されたモジュールをコンパイルする時点でコードを生成する。
そうじゃないと、doubleを使う度に毎回doubleをコンパイルすることになって、
分割コンパイルの恩恵が薄れる。(C++はあえてこれをやってるわけだが)
それから、Haskellの仕様上、完全に静的に済ますわけにはいけない。
newtype P a = P a deriving Show
nq :: (Show a) => Int -> a -> String
nq 0 x = show x
nq n x = nq (n-1) (P x)
こういう関数をtemplate式でコンパイルしようとしたら、無限にnqのインスタンスを生成する必要がある。

あと、実際にはdoubleのような小さい関数はインライン化されるので、ディスパッチが省略される可能性はある。

200:196
07/11/18 14:27:36
>>199
なるほど、値(この場合Int)に依存してどういうインスタンスのコードが
実行されるかが決定する場合があるってことか

201:デフォルトの名無しさん
07/11/18 14:34:20
1:2:3:[] -> [1,2,3]
↑がこうなるのはわかるんですが
1:2:3 -> ?
とやった場合はどんなデータができるんでしょうか?

202:186
07/11/18 14:42:10
3はリスト型じゃないからエラーになるんじゃないかな?

203:デフォルトの名無しさん
07/11/18 14:43:06
あ、名前欄消すの忘れてた……

204:デフォルトの名無しさん
07/11/18 14:46:12
>>201
(:) :: a -> [a] -> [a]

205:デフォルトの名無しさん
07/11/18 14:48:27
>>201
やってみりゃいいじゃん。それで挙動に疑問があったらここでもう一度聞いてみな。

206:201
07/11/18 15:25:47
やってみたんですがテキストに書いてコンパイルしようとするとエラーに
なるのにghciで:t 1:2とやると
1:2 :: (Num t, Num [t]) => [t]
というなんだかよくわからないメッセージが出ます。
:tだと型チェックしないのかなと思ったんですが
:t putStr 1
とやると今度はきちんとエラーが出ます。
・1:2 :: (Num t, Num [t]) => [t] は一体どういう意味なのか
・なんで:t 1:2はエラーにならないのに:t putStr 1はエラーになるのか
↑2つになる理由は何故なんでしょうか?

207:デフォルトの名無しさん
07/11/18 15:43:17
>>206
GHCは型クラス周辺を微妙に拡張してるからそのせいだろう。
Haskell98では(Num [t])という文脈はありえない。
Hugsで :t 1:2 と入れたらエラーが出たし。

208:デフォルトの名無しさん
07/11/18 15:44:43
ghcはIOの実装も特殊なんだよなー

209:デフォルトの名無しさん
07/11/18 15:53:43
一応解説。
Haskellでは1とか7とかの整数リテラルは(Num a) => aという型を与えられる。
つまりNumのインスタンスなら何にでもなり得る。具体的にはIntでもIntegerでもRationalでもいいし、
未知のユーザー定義型でもいい。
「1:2」という式では、とりあえず「1」の型をtと書くと、整数リテラルだから(Num t)という制約が必要。
(:)の右辺の型は左辺の型のリストだから、「2」の型は[t]。これも整数リテラルだから制約(Num [t])も要る。
式全体の型は右辺と同じで[t]だから、結果として(Num t, Num [t]) => [t]になる。

210:201
07/11/18 16:16:46
やっと理解できました。ありがとうございます。

211:デフォルトの名無しさん
07/11/18 16:19:47
なるほど、どこかで instance Num [Int] のようなことが
書かれていないとも限らない、ということですか。

212:デフォルトの名無しさん
07/11/18 16:44:20
すいません
初歩的な質問でごめんなさい。

main = do
 cs <- getContents
 putStr.unlines $ lines cs

これはコンパイル通るんですが

main = do
 cs <- getContents
 putStr.unlines.lines cs

これは通りませんでした…これって何故なんですか?
てっきりlinesとunlinesというのは対になってるもんだと思ってたんですが…

213:デフォルトの名無しさん
07/11/18 16:50:06
putStr.unlines.lines $ cs
なら通るよ。
関数適用とか演算子の優先順位の問題だね。

f $ g x == f . g $ x /= f . g x

214:デフォルトの名無しさん
07/11/18 16:55:54
うろ覚えだが関数抽象より関数適用のほうが優先されるので、
「putStr.unlines.lines cs」の部分が

putStr.unlines.(lines cs)

って解釈されるはず

main = do
 cs <- getContents
 (putStr.unlines.lines) cs

ならたぶん通る


215:デフォルトの名無しさん
07/11/18 16:58:16
二項演算子の周りにはスペースを入れようぜw

216:デフォルトの名無しさん
07/11/18 17:00:37
C言語で、関数と括弧の間にスペース空ける人?

217:デフォルトの名無しさん
07/11/18 17:09:39
いや、そこは詰める
まあ>>215をあまり真に受けないでくれ

218:デフォルトの名無しさん
07/11/18 17:23:42
(.) の周りにはスペースを入れない派なんだが
f.g x.h のように関数が引数を持つ場合にやるとなんか微妙

219:デフォルトの名無しさん
07/11/18 17:25:16
関数合成が関数適用より優先度低いのが許せない。
こう決めた理由はあるの?

220:デフォルトの名無しさん
07/11/18 17:25:37
Haskellの解説文を読んでいて、どっかで見たことある書き方だなぁと
思ったら、数学の教科書とソックリです。

つまり、Haskellは数学ができる人向けってことでしょうか?

221:デフォルトの名無しさん
07/11/18 17:31:13
>>213-214
うお、通りました。ありがとうございます。
関数合成と関数適用の優先順位の問題だったんですね。


222:デフォルトの名無しさん
07/11/18 18:15:00
>>219
関数適用最強の原則を守るためじゃないか?
俺は現状で満足だ。
map (fromMaybe 0 . fst) xs
とか書けるし。

223:デフォルトの名無しさん
07/11/18 18:34:32
>>219
うざい括弧をつけなくて済む

224:デフォルトの名無しさん
07/11/18 20:16:16
  (f.g) x
 ↑↑うざい括弧

225:デフォルトの名無しさん
07/11/18 20:23:03
f.g $ xじゃね?

226:デフォルトの名無しさん
07/11/18 20:42:38
>>224
C言語風には f(g(x))
うざくない?

227:デフォルトの名無しさん
07/11/19 03:14:41
URLリンク(hpcgi2.nifty.com)
このページの2007-07-04の日記を参考にプログラムを書いているのですが
これで横型探索できる理屈がまったくわかりません

228:デフォルトの名無しさん
07/11/19 03:39:03
Stateモナドについて質問なんですが
instance Monad (State s) where
         m >>= k = State $ \s -> let
          (a, s') = runState m s
          in runState (k a) s'

↑の式でm >>= k が m >> kなら、右辺は
State $ \s -> let
(a, s') = runState m s
in runState k s'
((k a)がkだけになる)
という風になると考えていいんでしょうか?


229:227
07/11/19 04:04:21
227ですが一応目処が立ちました。

230:デフォルトの名無しさん
07/11/19 04:24:37
>>228
それでOK。
ただm >>= kとm >> kのkはそれぞれ別の型だってことに注意。

m1 >> m2 = m1 >>= const m2 なので k=const m2 と考えると
runState (k a) s'
= runState ((const m2) a) s'
= runState m2 s'

231:228
07/11/19 10:59:03
うーん、難しい
>>=が一つだけならなんとか頭で理解できるんですが>>=が二つ以上ならんでいたり
do式で表されていたりすると脳味噌が追い付きませんorz

232:143
07/11/19 23:12:23
*GHC-6.6.1のクロスコンパイルについて公式ページのwikiに書いてない部分*

<ターゲット、ホストに共通>
デフォルトサーチパスにGNU MPがない場合は--with-gmp-{includes,libraries}で指定する必要があるが、
途中からこの指定(ライブラリサーチパス)を見てくれなくなる上、
できあがったGHCでも-Lオプションを指定しなければいけなくなるので
(少なくともlibgmp.so.*かlibgmp.aファイルのどちらかを)デフォルトサーチパスにシンボリックリンクしておくほうがいい。

<ホスト>
ghc-6.6.1/Makefileの
echo ghc-$(ProjectVersion)/libraries/haskell-src/Language/Haskell/Parser.hs >> hc-files-to-go
という行を削除またはコメントアウトする必要がある。

libraries/Cabal/cabal-setup/CabalSetup.hsが作られないので、
cd compiler && make boot && makeの後、
cd libraries/Cabal/cabal-setup
rm CabalSetup.{o,hi} cabalsetup
../../../compiler/ghc-inplace -H16m -O -H32m -package Cabal -c CabalSetup.hs -o CabalSetup.o -ohi CabalSetup.hi -keep-hc-files
../../../compiler/ghc-inplace -o cabal-setup -H16m -O -H32m -package Cabal CabalSetup.o
する必要がある。

make hc-file-bundle Project=Ghcの前に、
make -C rts AutoApply_thr.hc AutoApply_thr_p.hc AutoApply_debug.hc AutoApply_thr_debug.hc
する必要がある。

続く

233:143
07/11/19 23:14:33
*GHC-6.6.1のクロスコンパイルについて公式ページのwikiに書いてない部分* 続き

<ターゲット>
いきなり/usr/localにインストールするのではなく、stage1のためのディレクトリにインストールして、
それを利用してもう一度ghcをビルドしたほうがいいと思われる。

*-hc-tar.gzをソースツリーにコピーするのではなく、展開されるghc-6.6.1を手動でソースツリーに上書きする必要がある。

distrib以下のスクリプトに実行権限を与える必要がある。

hc-buildが完了した後、
cd compiler
rm -f *.hs-incl
make primop-can-fail.hs-incl primop-commutable.hs-incl primop-data-decl.hs-incl
primop-has-side-effects.hs-incl primop-list.hs-incl primop-needs-wrapper.hs-inc
l primop-out-of-line.hs-incl primop-primop-info.hs-incl primop-strictness.hs-inc
l primop-tag.hs-incl primop-usage.hs-incl
find . -name \*.o -exec rm {} \;
make boot stage=1 && gmake stage=1
cd ..
make install stage=1
で完了。

ちなみにザウルスのOpenBSD上では16MB以上のテキストセグメントがある実行ファイルは実行できないので
テキストセグメントを32MBに拡張したカーネルを使用しなければビルドできませんでした。
GNU makeがmakeという名前以外(gmakeなど)でインストールされている場合は、適宜読み替えてください。
かなり効率の悪い方法なので、Makefile等をちゃんと読めばもっと最適化できると思います。

古いGHCで新しいGHCをビルドするのはうまくいきますが、
新しいGHCで古いGHCをビルドするのはなかなかうまくいきませんね。

234:デフォルトの名無しさん
07/11/20 08:39:00
一度評価された式をもう一度評価しようとする場合って、再度最初から評価しなおすんですか?

例えば
add x y = x + y
という関数があって、一度
add 1 2
という式を評価した後もう一度
add 1 2
を評価しようとするとき、内部では律儀に 1 + 2 を行うんでしょうか?それとも
add 1 2 = 3
みたいな式が内部で作られてたりするんでしょうか?

235:デフォルトの名無しさん
07/11/20 09:30:04
↑の場合は俺も知りたいです

俺が知ってるのは
f x a b c = a*x*x + b*x * c
という関数に対して
f (1+2) 3 4 5
と呼び出した場合に1+2が1度しか評価されないことくらい…

236:デフォルトの名無しさん
07/11/20 10:20:01
>>234
Haskellの規格では規定されてないけど、普通は評価しなおす。
関数を全部メモ化していたら、救いようのないメモリリークが起こるはず。ただし、
map (\x -> x * add 1 2) xs
のようなコードが最適化されて
let _z = add 1 2 in map (\x -> x * _z) xs
になって、add 1 2が一回しか計算されない、という場合はある。

237:デフォルトの名無しさん
07/11/20 11:41:31
>>234-235
コンパイラのコンパイルオプションによっても動作が違うかな

import System.IO.Unsafe
f n=seq (unsafePerformIO $ putStrLn "hello") n

a=f 1+f 1

main=print a

のようなコードだとGHC6.6.1の場合で最適化なしの場合とありの場合でhelloの表示回数が違ったりする。


238:237
07/11/20 11:44:46
追記

a=f 1+f 2

でも最適化ありで1回表示、 無しで2回表示でした。


239:デフォルトの名無しさん
07/11/20 18:31:21
質問なのですが、
ドラキュラとかが眠ってそうな感じの、棺おけ型のベッドというのは市販されているのでしょうか?
冬の暖房の時期に、部屋ごと暖めるのでは効率が悪いので、棺おけの中だけ温度調節できれば
コスト安になると思ったのです。
また、フタをつけるので静かですし、明かりもシャットアウトできてよいと思うのです。

240:デフォルトの名無しさん
07/11/20 19:04:23
ドラキュラとかが眠ってそうな感じの、棺おけ型のベッドというのは市販されているのでしょうか?
(計算をデフォルトで遅延させる機能のある、関数型のプログラム言語は市販されているのでしょうか?)
冬の暖房の時期に、部屋ごと暖めるのでは効率が悪いので、
(評価されない可能性のある式を正格に評価するのは効率が悪いので)
棺おけの中だけ温度調節できればコスト安になると思ったのです。
(必要になってから評価できれば計算コストを削減できると思ったのです。)
また、フタをつけるので静かですし、明かりもシャットアウトできてよいと思うのです。
(一度評価されればメモ化されるので計算量が少なくなりますし、バグの混入もシャットアウトできてよいと思うのです。)

答え:Haskellは無料で公開されています

こうですか!? わかりません!


241:デフォルトの名無しさん
07/11/20 19:27:37
感動した

242:デフォルトの名無しさん
07/11/21 04:31:54
質問です

GHC6.8.1にはHGL入ってないんですか?

243:デフォルトの名無しさん
07/11/22 01:59:38
Windowsアプリ作っていて気づいたんだが、
Win32モジュールにはSetLayeredWindowAttributesのラッパは入ってないんだな・・
自作するしかないんだろうか。

244:デフォルトの名無しさん
07/11/22 07:26:41
書いてパッチを送るんだ!

245:デフォルトの名無しさん
07/11/22 12:20:00
>>244
>書いてパッチを送るんだ!
いや、これってwindows2000以降の機能で、Win32モジュールに入れるべきかどうか正直迷うんだよね。

246:デフォルトの名無しさん
07/11/22 23:16:48
Windows2000以降のラッパをまとめたWin32exモジュールを作ったので公開しました。
ツッコミなどよろしく。

247:デフォルトの名無しさん
07/11/23 09:58:22
>>245
Windowsに詳しくないので間違ってたら済まんが、2000以降のみの関数も
普通にwin32パッケージに入ってないか?setConsoleCPとかfindFirstChangeNotificationとか。

>>246
どこに置いたかも書けよw

248:デフォルトの名無しさん
07/11/23 10:06:51
246はPeyton Jonesだ。

場所は、わかるだろ。

249:デフォルトの名無しさん
07/11/26 23:05:20
関数型言語はマルチコア時代にフィットしているという話を聞いたことがあります。
既存の流行している言語は対応できてないと。

これはどういう理由でしょうか?遅延評価とか、その辺のことを指しているんでしょうか。

250:デフォルトの名無しさん
07/11/26 23:13:40
知らんけどミュータブルな値があるとスレッドセーフにならないとかそういうへんの話じゃね?

251:デフォルトの名無しさん
07/11/26 23:23:18
MapReduce の「副作用が無ければ無限にスケールする」というのが
一人歩きしてるだけじゃないかな。実際には何をするにも副作用は
あるし、MapReduce だって Reduce の作業はスケーラビリティが
殆ど無いか少ない。関数型言語には副作用が無いというのと同じ様な
勘違い。ただ副作用が無い=スケールする部分を奇麗に切り出せる
のであれば有用ではある。

252:デフォルトの名無しさん
07/11/27 11:43:41
ああいう大規模データパラレルとマルチコアはあんまり関係ないじゃん。
>>249の話は伝聞なんで雲を掴むような話だけど。


253:249
07/11/27 11:48:13
ありがとうございます。透過参照性がスレッドセーフというのはよく分かります。

遅延評価っていうのは、別に関係ないんでしょうか。何かそっちの話を聞いた
ことがあるんです。自分の初心者脳では、正格では無限のリソースを前提に
した関数を書けないが、Haskellのような言語だと記述可能、とか思ったのですが、
ちょっと頭悪いですか?w

254:デフォルトの名無しさん
07/11/27 12:16:38
遅延評価や投機実行をうまく使えば、
CPUコアの利用効率を上げられますが、
それには頭のいいスケジューラが必要なわけで。

例えば、
URLリンク(www.fixstars.com)
にプチ解説があるようなstragglersの問題。

ただ実行順序が規定されてないので、
工夫する余地がまだまだ残されているとは言えると思う。
Erlangのような言語が、あまりpure functionalじゃないとはいえ、
一通りの実績を上げていますし。

また、プログラマがスケジューラに自由を与えるような
プログラミングスタイルを強制されているという見方もあると思う。



255:デフォルトの名無しさん
07/12/06 10:41:19
F#のスレは毎日更新されてますが、こちらは静かですね・・・

関数型で今イチバン売れ筋なのはF#なんですかね。

256:デフォルトの名無しさん
07/12/06 17:36:48
Haskell始めてから3週間目の今の感想。
・概念的にはMonadよりArrowのほうが分かりやすいんじゃないか?とか。
・Monadって何?って聞かれるとなんと答えていいかわからないが、
  Arrowなら『矢印をカプセル化したようなもの』と言える。
  あとは適当に結合演算とか普通の関数をアロー化する演算とか実装していけばおk。
  脳内のイメージも矢印をつないでいくだけだし。
  Monadをイメージしようとしてもなんかいまいちピンとこない……。
  bindにやる夫関数とか適当に名前を付けて無理矢理イメージしたけど。
・Monadのbind演算子(>>=)はm a -> (a -> m b) -> m bで非対称的。
  Arrowの(>>>)はa b c -> a c d -> a b dで比較的対称性があって気持ちよい。
・Arrowは『計算を結合』しているのが自明的に表現されてる。
  Monadは別にそうは見えない。……値と計算を結合なのか?意味わかんね。
・そもそも非対称な二項中置演算子はイマイチ気に入らない。
  リスト結合演算子とか`elem`とかは仕方ないけど、せめてあまり高階にしてほしくない
・Monadの計算部(a -> m b)は結構重要なパーツの一つなのに、名前が付いてない。
  だから『モナドを返す関数』としかいえねえ。
  しかもbindした後にはその返り値とは(型は同じだけど)別の奴が帰ってくる。無駄に混乱。
  その点Arrowは計算部がずばり『Arrow』。カプセル化されていて美しい。
・Monadは(>>=)は左から右へ流すように使えるが
  普通の関数は右から左。もちろんliftMとかも右から左。
  (=<<)も右から左。しかし関数を拡張して適用するという見方で見るとこっちが自然という謎さ。
  結局どっちからどっちへ読むべきか迷う場所が多く、思考停止してしまう。
  ArrowだったらArrowとして結合されている部分は左から右。
  普通の関数は右から左で思考が自然に切り分けられる。

257:デフォルトの名無しさん
07/12/06 17:37:32
・Monadでポイントフリースタイルをやろうとするとかなりキモくなるよね。
  Arrowはまあ基本的にポイントフリーな感じがするし、普通の関数と分けられていいんじゃない?
・Arrowの構造を作ったりする関数は基本的にArrowだけを返す。
  Monadの関数はなんかリストとかに入ってたりして気味が悪い。モナドのリストって、最中十個入りじゃないんだから。
・Arrowの構造を作る関数はキチンと構造を作ってるように見える。
  Monadの場合は解読に時間がかかる。なんのためにこんな書き方をしてるんだろうとか……。
・ArrowでStateを自作してみたら比較的分かりやすかった。
  Monadのは今見ても訳が分からん。というかMonadの対象が関数って何だよ。
・Monadに慣れ親しんでる人はMonadを扱うのに苦労しないだろうから、
  簡単なものなら短い表記が出来るMonadのほうがいいんだろう。
  しかし、初心者にいきなり教えるのならArrowのほうが直感的。
  ポイントフリースタイルを使いまくってムツカシイことさえしなければ。
・Arrow講座みたいな入門編とかでArrowを書くとき、
  関数がそのままアローになるからってやたら省略しないでいただきたい。
  アローな部分と普通の関数の部分が綺麗に分かれてるのがいいんだから……
  それにarrってやっておけばその部分は一般のArrowでも使えるし。
  SF f >>> SF g = SF (f >>> g)とか出来るからそういう書き方が出来ること自体はありがたいが。
・arr.uncurryとかarr.constってよく出てくるけどそういう関数はないのか……
・Arrow関係ないけどデータ構築子と型構築子が同じ名前って混乱するな。時々イラっとくる。
・aとかbとか何を表してんのか直感的じゃねえよ。型変数だったり、引数だったり……
  fって名前だから関数かと思いきやArrowだったり。
  ネーミング規約みたいなものはないのか……
  Arrowが引数で来たときの名前の付け方とかおもいつかねえけど。
・そろそろふつける買おうかな……。
・初心者のくせに身の程をわきまえない長文失礼しました……

258:デフォルトの名無しさん
07/12/06 17:42:34
>>257
> ・Monadでポイントフリースタイルをやろうとするとかなりキモくなるよね。
もう少し他人のコードを読んでいくと感覚がつかめてくると思いますよ

259:デフォルトの名無しさん
07/12/06 18:11:18
モナドのリストを返す関数なんてそんなに使うか?

しかし「モナドのリスト」って言い方は何か違和感あるな。
[IO]みたいなのを想像してしまう。

260:デフォルトの名無しさん
07/12/06 18:16:50
俺のポリシーではIOはmain内でしか使わない

261:デフォルトの名無しさん
07/12/06 18:25:06
>>258
把握。

>>259
ライブラリを見返してるけどそこまではなかったかも……。
初めて見たときに比べればそこまで疲れないし。
やっぱり慣れの問題なんだろうか。『モナドを返す関数』が普通の関数と同じ地位にいるのがイマイチだけど。
引数の数でバージョンがいくつもあったりするのもなんかいただけない。
でもやっぱり慣れれば気にならなくなるんだろうな……。
なんかJavaやったらCのポインタが理解できた時の気持ちを思い出した。(違うか)

262:デフォルトの名無しさん
07/12/06 18:30:02
モナドなんてステートとIOとリストとMaybe以外はほとんどつかわねーぜ

263:デフォルトの名無しさん
07/12/06 18:30:44
IORefもつかうか。

264:デフォルトの名無しさん
07/12/06 18:38:36
a0 -> a1 -> ... -> m bの形の関数を呼ぶのにはmonadic functionという名前が使えるはず。
日本語だと「モナドな関数」か。

俺のコードの大部分はモナドな関数になってるな。
普通の関数より書きにくいから嫌なんだが、変更に強いコードにするために仕方なく。

265:デフォルトの名無しさん
07/12/08 12:05:09
やさしいHaskell入門での質問です。

URLリンク(www.sampou.org)
> (ここで、同値性といっているのは、「値同値性」のことです。
> 対照的な概念としては、「ポインタ同値性」というのがあります。
> たとえば、Java 言語の == です。
> ポインタ同値性は参照透明性を持ちません。
> それゆえに純粋な関数型言語とは相性がよくありません。)

なぜポインタ同値性は参照透明性を持たないのですか?

266:デフォルトの名無しさん
07/12/08 12:26:42
>>265
ポインタ同値をテストする関数eqがあったとすると、
let v = [1,2] in eq v v
はTrue。一方、vを展開して
eq [1,2] [1,2]
とするとFalseになるかもしれない。
参照透過って言うのはそもそも、こういう展開をしても
プログラムの意味が変わらないってことだから、
eqによって参照透過性が破られたと言える。

267:265
07/12/08 12:37:55
>>266
おー!なるほど。わかりやすい説明ありがとう。
[1,2] が複数箇所に出現する場合、メモリ上に別々に配置されるかもしれないわけですね。
勉強になりました。

268:デフォルトの名無しさん
07/12/09 15:29:39
『A a』っていう表記が使われる場所によって
Aは型構築子、全体は多相型、aはパラメータ
Aはデータ構築子、全体はデータ構造、aはその中身
aは型クラスAのインスタンス、何かの型の一部
って変わるのがちょっとわかりにくいね。もうちっとなんとかならんか。

269:デフォルトの名無しさん
07/12/09 21:35:19
Haskell勉強してなくてよくわからないんですが、
乱数生成器をsplitしていくつかにしてseed固定で乱数を作れといわれました。
どう作ればいいんでしょうか?
初歩的な質問だったらすみません。

270:デフォルトの名無しさん
07/12/10 00:51:19
日本語でおk

271:デフォルトの名無しさん
07/12/10 15:07:15
無限リストって便利だけど、末尾を正格に要求する関数について型安全じゃないよね。
でも無限リスト型を再定義するとリストに関して作ったすべての関数について委譲関数を作んなきゃいけなくて現実的じゃない。
結局これは妥協するしかないのか?それともなんらかのテクニックで回避できる?


次ページ
最新レス表示
スレッドの検索
類似スレ一覧
話題のニュース
おまかせリスト
▼オプションを表示
暇つぶし2ch

5218日前に更新/201 KB
担当:undef