1 名前:デフォルトの名無しさん [04/02/10 22:16] Haskellの公式HP www.haskell.org/ 日本語サイト www.sampou.org/cgi-bin/haskell.cgi www.teu.ac.jp/kougi/koshida/Prog6/index.html 過去ログ、関連スレは>>2-5
151 名前:デフォルトの名無しさん mailto:sage [04/08/14 01:49] 誰か「モナドだけで書く Haskell プログラミング」を書いてくれい
152 名前:デフォルトの名無しさん mailto:sage [04/08/15 13:29] >>151 Cでも使ってれば?
153 名前:デフォルトの名無しさん mailto:sage [04/08/15 21:34] そういやHaskellのコンパイルはC経由なんだよね
154 名前:デフォルトの名無しさん mailto:sage [04/08/15 22:04] 末尾再帰の保証とかC経由じゃ無理だろ
155 名前:デフォルトの名無しさん mailto:sage [04/08/15 22:21] GHCで最適化オプション付けるとCのコード吐くんじゃなかったっけ?
156 名前:デフォルトの名無しさん mailto:sage [04/08/16 02:59] >>150 メール出して聞いたら? ttp://www-maths.swan.ac.uk/staff/jrh/ J. Roger Hindley ttp://www.cl.cam.ac.uk/~rm135/ Robin Milner
157 名前:デフォルトの名無しさん mailto:sage [04/08/16 05:57] >>156 もちつけ
158 名前:デフォルトの名無しさん mailto:sage [04/08/16 06:12] >>154 そりゃ当然、Cにする前にプログラム変換するだろ それに大抵のCCには-foptimize-sibling-callsみたいなのがあるだろうし
159 名前:デフォルトの名無しさん mailto:sage [04/08/16 08:24] レベル低いな。っつってもHaskellのことは何も知らないのであれなんだが。。。 ユーザーレベルで言語をマスターするっつーのは、ある処理系を骨までしゃぶり 尽くすことだろ。リスパーのように自作こそ最強だが、複雑な言語ではそこまでは まあ、なかなか出来るもんでもないしな。 GHCのことについて詳しい奴がいないのを見ると、誰もHaskellでまともに プログラム書こうとしてないように見える。結局おまいらは、話のネタに 関数型言語を選んでるだけなんだよ。
160 名前:デフォルトの名無しさん mailto:sage [04/08/16 23:20] ↑Aransk?
161 名前:デフォルトの名無しさん mailto:sage [04/08/17 00:31] Simon Peyton Jones は C-- もやってるのに、自前でオプティマイズ出来ないってのは意外。
162 名前:デフォルトの名無しさん mailto:sage [04/08/17 00:50] >160 Aranskはいちゃもん言うだけでプログラムすら書かんだろ?
163 名前:デフォルトの名無しさん mailto:sage [04/08/18 12:47] wxhaskellについてですが、 サンプルプログラムのBouncingBalls.hsでセグメンテーションフォールトが 起きます。(wxhaskell.sourceforge.net/quickstart.html ) プログラムを起動し、'p'などのアルファベットを入力することで生じます。 そこで小さなプログラムを作って試してみたのですが、 やはり同様な現象が起ります。 $ cat test.hs import Graphics.UI.WX main :: IO () main = start test test :: IO () test = do f <- frame [] p <- panel f [] set f [layout := widget p] set p [on(charKey 'a') := print "test ok"] $ ghc -package wx test.hs -o test $ ./test (ここでキーボードの'a'を入力) セグメンテーション違反です 環境 wxhaskellのバージョンは0.7 wxGTKのバージョンは2.4.2 OSはlinux 他の環境でもこのバグが再現するでしょうか。
164 名前:デフォルトの名無しさん mailto:sage [04/08/19 17:20] >>163 特に問題発生せず 環境 wxHaskell 0.8 wxWidget 2.5.2 MacOS X 10.3 $ ghc -package wx test.hs -o test $ /usr/local/wxhaskell/bin/macos-app -v test できたtestをFinderからダブルクリックで起動 真っ白いパネルが出てくる 'a' 押すと「コンソール」に "test ok" とりあえずバージョンアップしてみれば
165 名前:デフォルトの名無しさん mailto:sage [04/08/22 09:05] wxHaskellを0.8にバージョンアップしたら問題は解決しました。 どうもありがとうございます。
166 名前:デフォルトの名無しさん mailto:sage [04/08/22 09:36] このような関数はどう書けばいいんでしょうか? f (+) [1 2 3] [4 5 6] => [5 7 9]
167 名前:デフォルトの名無しさん mailto:sage [04/08/22 11:30] f g (x:xs) (y:ys) = (g x y) : f g xs ys
168 名前:デフォルトの名無しさん mailto:sage [04/08/22 11:41] f g xs ys = [g x y | (x, y) <- zip xs ys]
169 名前:デフォルトの名無しさん [04/08/22 11:55] これを拡張したn引数(n階?)の関数とn個のリストをとる 関数はどう書くのがいいでしょう。 f n g [x11, x12, ...] [x21, x22, ...] ... [xn1, xn2, ...] => [(g x11 x21 ... xn1), (g x12 x22 ... xn2), ...] みたいな。lispのmapってこんな感じですよね。あちらは 関数のarityがわかるからnは不要ですけど。
170 名前:デフォルトの名無しさん mailto:sage [04/08/22 12:19] f g = map (hoge g) $ zip Haskellはよく知らんので、hogeをどうやって書くのか調べてもよく分からん。
171 名前:デフォルトの名無しさん mailto:sage [04/08/22 16:24] 引数の数が可変ってhaskellでは書けないような気が。 何か方法あったっけ?
172 名前:デフォルトの名無しさん mailto:sage [04/08/22 16:45] >>166 zipWith (+) [1, 2, 3] [4, 5, 6]
173 名前:デフォルトの名無しさん mailto:sage [04/08/22 17:19] >>171 別に可変個の引数は必要ない。 1引数の関数のリストと引数のリストを受け取って適用して返す演算子をつくればOK。 演算子をxとすると [f, f, f] x [x11, x12, x13] x [x21, x22, x23] とか。Haskellの細かい文法知らんのでこう書けるかどうかは知らないけど。
174 名前:デフォルトの名無しさん mailto:sage [04/08/22 17:48] どういう型になるんだ?
175 名前:デフォルトの名無しさん mailto:sage [04/08/22 17:53] map sum $ transpose [[1,2,3],[4,5,6],[7,8,9]] => [12,15,18] こんなもんでどうでしょうか。
176 名前:デフォルトの名無しさん [04/08/22 20:04] >>174 [a->b]->[a]->[b]かな?
177 名前:デフォルトの名無しさん mailto:sage [04/08/22 20:10] zipWith ($)
178 名前:デフォルトの名無しさん [04/08/22 20:54] Prelude> (zipWith ($)) (map (+) [1,2,3]) [4,5,6] [5,7,9] ナルホド。
179 名前:デフォルトの名無しさん [04/08/23 11:43] 只の関数適用(f x)と(f $ x)って何か違うところあるの? それとも( )じゃワケがわからないから($)と書けるように 目に見える演算子として用意されているだけ?
180 名前:デフォルトの名無しさん mailto:sage [04/08/23 12:19] $ は関数合成では?
181 名前:145 mailto:sage [04/08/23 12:35] 関数合成は . でしょ。 >>179 何も代わらない。関数適用のための演算子だから。 本来の利用法は >>178 みたいなものなのかな(個々の要素にそれぞれ適用する ためには、関数適用の演算子があると便利)。 f $ g x と書くと、演算子の優先度の関係上 f(g x) と同じことになるので便 利、ついでに結合性の関係で f $ g $ h x とか書ける、というのが個人的に は嬉しい。カッコの省略にも使える。 関数合成はあくまで関数の合成の演算子なので、 f . g . h x とは書けない。 (f . g . h) x なら書けるけど。
182 名前:デフォルトの名無しさん mailto:sage [04/08/23 16:17] 可変個数の zipWith については、 Functional Pearl "Do we need dependent types?" Daniel Fridlender and Mia Indrika, 2000 J. Functional Programming, vol. 10, July. ttp://www.cs.chalmers.se/~indrika/publication.html に載っているので興味があるひとは読んでみるべし。
183 名前:デフォルトの名無しさん mailto:sage [04/08/24 12:40] >>171-181 > 只の関数適用(f x)と(f $ x)って何か違うところあるの? ある。$はただの関数だから、引数の型がそこで固定される。 f :: a -> (forall b. b -> b) -> a f x g = g x とすると、f 0 id はOKだが、f 0 $ id はだめ。 ST Monadなんかをつかっていると結構引っかかる。
184 名前:デフォルトの名無しさん [04/08/24 14:37] -- zipWithN infixl 2 <$> infixl 1 <-> (<$>) = map (<->) = zipWith ($) -- 例 -- (\x y z -> x + y + z) <$> [3,4] <-> [5,6] <-> [7,8] ---------------------------- -- 可変引数 ncat :: NCat b => b ncat = ncat' id class NCat a where ncat' :: (String -> String) -> a instance NCat String where ncat' f = f "" instance NCat b => NCat (Char -> b) where ncat' f x = ncat' (f . (x:)) -- 例 -- ncat 'a' 'b' 'c' # >>183 の171は179の間違い。
185 名前:デフォルトの名無しさん mailto:sage [04/08/24 14:38] >>184 型指定が要った。 ncat 'a' 'b' 'c' :: String
186 名前:デフォルトの名無しさん mailto:sage [04/08/24 20:08] 携帯から読むと AA 判定されててワラタ >>183-185
187 名前:デフォルトの名無しさん mailto:sage [04/08/26 20:44] AA的プログラミング
188 名前:デフォルトの名無しさん mailto:sage [04/08/26 20:54] (--#) とか (*^-^*) とか?
189 名前:デフォルトの名無しさん mailto:sage [04/08/30 23:20] Categories for the Working Mathematician の訳書ってなんていうタイトルでつか?
190 名前:デフォルトの名無しさん mailto:sage [04/08/30 23:27] スマソ。 「そのうち出る」 = 「そのうち出版される」という意味か。 「テキストの候補に挙がる」ではなく。
191 名前:デフォルトの名無しさん mailto:sage [04/08/31 00:44] 誤爆にも程があります
192 名前:デフォルトの名無しさん mailto:sage [04/08/31 12:01] 「数学に勤しむ貴方のための圏論」てのがそれらしいが 近刊とあってまだ出てないようだ。 ttp://www.kyoto-su.ac.jp/~hxm/hxm.cc/research.ja.html
193 名前:デフォルトの名無しさん mailto:sage [04/09/07 17:30] 末尾再起すると、遅延評価されないですね。 (length (hoge xx yy zz)) < 3 とかで困る。かも。
194 名前:デフォルトの名無しさん mailto:sage [04/09/07 20:50] >>193 > 末尾再起すると、遅延評価されないですね。 そんなことはない。 > (length (hoge xx yy zz)) < 3 > とかで困る。かも。 lengthがstrictだからhogeがlazyでも意味がないとはいえるが、 末尾再帰とは無関係なので、意味がわからない。 なにを誤解してるのですか?
195 名前:デフォルトの名無しさん mailto:sage [04/09/08 10:49] >>193 『末尾再帰の最適化』をすると遅延評価できない(或いはその逆)、のことを言いたいのかな。 それだったら解る。 あ、でも例 (length (hoge xx yy zz)) < 3 の意味はやっぱりわからない。
196 名前:デフォルトの名無しさん mailto:sage [04/09/08 18:24] >>195 > 『末尾再帰の最適化』をすると遅延評価できない(或いはその逆)、のことを言いたいのかな。 詳しく説明きぼんぬ。 gotoでジャンプするコードにするとサンクが作れないのかな?
197 名前:デフォルトの名無しさん mailto:sage [04/09/09 23:56] >>195 take n 末尾再帰関数(無限リスト) みたいなのが出来ないということでは?
198 名前:197 mailto:sage [04/09/10 00:26] 括弧の位置を間違えた。 take n (末尾再帰関数 無限リスト ・・) です。
199 名前:193(初心者) mailto:sage [04/09/10 16:18:42] すいません。どっかいってました。 >197さんの言うとおりです。 例は適当にかいたらだめでした。
200 名前:デフォルトの名無しさん mailto:sage [04/09/10 16:25:19] >>197-198 なにができないと? take' 0 xs = xs take' n (x:xs) = take' (n - 1) xs take n (take' 10 [0..])
201 名前:197 mailto:sage [04/09/10 21:59:52] >>200 返値も無限リストの場合です。 nub0 :: Eq a => [a] -> [a] nub0 = nub0' [] nub0' l [] = l nub0' l (x:xs) | elem x l = nub0' l xs | otherwise = nub0' (x:l) xs take 10 (nub0 [1..])
202 名前:デフォルトの名無しさん mailto:sage [04/09/10 22:16:02] >>201 nub0 [1..]自体がbottom(無限リストではない)なんだから 末尾再帰も糞もないですよ。 nub0' :: [Int] -> Int nub0' = foldr (+) 0 だって同じこと。
203 名前:197 mailto:sage [04/09/10 23:25:33] いろいろと書き方がまずくてすみません。 nub0 を末尾再帰で定義したから、nub0 [1..] が bottomになったわけで、Hugsでの定義の nub l = nub' l [] where nub' [] _ = [] nub' (x:xs) ls | x `elem` ls = nub' xs ls | otherwise = x : nub' xs (x:ls) のようにすれば nub [1..] は無限リストになる、という意味です。
204 名前:デフォルトの名無しさん [04/10/07 21:01:01] いいかげん誰かモナドをわかりやすく説明してくんない? 関数型言語のキモは副作用とのコラボレーションなんだし
205 名前:デフォルトの名無しさん mailto:sage [04/10/08 02:06:46] >>204 www.sampou.org/haskell/a-a-monads/html/index.html ではだめ?
206 名前:デフォルトの名無しさん mailto:sage [04/10/14 01:54:56] んじゃ自分の理解度の確認を兼ねて。(突っ込みよろしく) モナドは数学上はモノイドといって単位元を持つ半群のこと。 一応簡単な説明。 (X * X ) * X = X * ( X * X ) といった「結合側」が成り立つ演算*があって (E * X ) = ( X * E ) = X となる単位元Eを持つようなXのこと。 X が整数だとすれば * は足し算 E は 0 もちろん * を掛け算 E は 1としてもいい。 * を文字列の結合 , Eを空文字列 "" とすれば文字列もモノイドとみなせる。 で、HaskellのIO型には 上の文字列モナド(モノイド)の1文字づつの代わりにOSのシステムコール呼び出しの機械語が 入っていると思えばいい。 IOモナドA( [キー入力] ) >> IOモナドB( [画面出力] ) を適用すると IOモナドC( [キー入力]の次に[画面出力] ) になる みたいな。 で どんどん >> や >>=で繋いでいくわけ。 もちろん結合則も成り立つ。 ちなみにreturn 関数が返すIO型が単位元になってる。 これはreturnの返すIOには何もシステムコール?が含まれてないから 上の文字列モナドの空文字列みたいな感じ これで宜しいでしょうか>>204
207 名前:デフォルトの名無しさん mailto:sage [04/10/14 03:55:12] >>206 Monoidだと思って話すなら: 結合法則: (a * b) * c = a * (b * c) を満たす演算*が定義されていて、 単位元 e (e * a = a * e = a をみたす) を持つような集合を Monoid(以下、単に半群という)といいます。 例えば"行列"や"微分方程式の解作用素"は半群になっています。 *** Point(1): a * b /= b * a。順序は変えられない この半群の集合への作用(注1)の仕方を定めたものがMonadです。 return == e で、あとは * にあたるものが >>= となります。 そういうと、return :: a -> M a (M "a" なのは単位元だから) なんだから、 >>= :: (s -> M t) -> (t -> M u) -> (s -> M u) じゃないのかと思うかも知れませんが、 >>= :: M t -> (t -> M u) -> M u でもいいのです。 というのは、(c * d)' x = c' (d' x)なので、*を決めることと、 M sの任意の元(d' x 等)をどこにうつすかを決めることは同じことだからです。 続く。
208 名前:207 mailto:sage [04/10/14 03:57:32] この行は前のメッセージの最後にあるべきでしたが、 *** Point(2): x /= y ならば a' x と a' y は等しくなくてもよい さて、例えばIOモナドなら、putStr :: String -> IO () は上のaやらbやらにあたります。ではgetLine :: IO Stringはというと、 元を一つしか持たない集合をUとしてgetLine :: U -> IO String の省略記法 なのです。元が一つしかないのだから、わざわざU->を考える必要はありません。 Point(1)、(2)がIOの、順序を変えられない、毎回違う答えが帰るかもしれない という性質を満足させてくれます。 main = getLine >>= putStr は、(putStr * getLine) と同じもので、 実行するのは putStr' (getLine' world) を計算することです。 getLineが毎回異なる文字列をputStrに>>=で与えても、それはworld が違ったからだと思えばなにも問題はありません。 *1 (作用) 行列をベクトルにかけるとベクトルができますが、これと同じように、 半群(M)の元(a, b, ..)をある集合(S)の上の関数とみなすことができます。 好き勝手に関数とみなすのではなく、次の性質をみたすとき、 半群MがSに作用している、ということにします。関数とみなすときには'をつけます。 (a * b)' x = a' (b' x) (x は S の元) # monoidとmonad (triple)はどちらも数学の概念で、似ていますが別物です。
209 名前:デフォルトの名無しさん mailto:sage [04/10/14 08:51:55] (X * X ) * X = X * ( X * X ) といった「結合側」が成り立つ の()の意味はなんだ? 単に型が合うかどうかか?演算の時間的な順番か?
210 名前:デフォルトの名無しさん mailto:sage [04/10/14 09:25:14] >>209 演算の順序。 代数の本を読めばどしょっぱなに書いてあるよ。
211 名前:デフォルトの名無しさん mailto:sage [04/10/14 09:29:17] じゃあ(入力 * 出力)* 入力 = 入力 * (出力 * 入力)になって 最初に出力してくれるのかい?
212 名前:デフォルトの名無しさん mailto:sage [04/10/14 11:05:33] コードの結合順序と、実行順序を混同するな。 Cで {{f(); g();} h();} と {f(); {g(); h();}} が同じ結果になる みたいなものだ。
213 名前:デフォルトの名無しさん mailto:sage [04/10/14 15:33:35] だから(X * X ) * X = X * ( X * X )ってのはどういう意味なの?
214 名前:デフォルトの名無しさん mailto:sage [04/10/14 16:42:30] >>213 モノイドの説明だとしたら、その式はそうとしか言えないのでは。整数上の加 算について考えると、 (1+2)+3 = 1+(2+3) が結合則。 1+0 = 0+1 = 1 が単位元の性質ということ。数学の話だよ。 モナドだとすれば、 >>207-208 じゃないのか。 (f * (g * h)) x = ((f * g) * h) x = f(g(h(x))) という風に理解したんだがこれは当ってる? Haskell の記法を使えば、 x >>= (\x -> x >>= h >>= g) >>= f = x >>= h >>= (\x -> x >>= g >>= f) かな? モナドというのは、「評価の順序を保証するもの」という風に考えているんだ が、その事を「結合則は成立するが、交換則は成立していない」という事で表 現しているということなのでは。 副作用の話は 208 の方に書いてあると思うんだが、こっちはよくわからない……。
215 名前:デフォルトの名無しさん mailto:sage [04/10/14 17:00:35] >>214 > 「結合則は成立するが、交換則は成立していない」 「交換則は必ずしも成立するわけではない」のほうが適当では?
216 名前:デフォルトの名無しさん mailto:sage [04/10/14 17:05:38] この場合の(X * X ) * X = X * ( X * X )の意味は どういう風に括弧をつけても関数Xの適用順序は 左から右、右から左と一定であるって意味でいいの?
217 名前:デフォルトの名無しさん mailto:sage [04/10/14 17:17:39] >>215 ああその通りですね。失礼しました。 >>213 =216 まあその通りといえばその通りではないかと思います。 *を関数の合成みたいな演算だと考えればよいのでは。
218 名前:デフォルトの名無しさん mailto:sage [04/10/14 17:22:34] で、208に質問なんですが、 > *** Point(2): x /= y ならば a' x と a' y は等しくなくてもよい はわかるとして、 GetLine :: U -> IO String であり、 U が一点集合なのだ としたら、これは x = y である(にもかかわらず a' x /= a' y になりうる) 例のように読めてしまったのですが、どこで間違えているんでしょうか? getLine' world というのは、常に world が与えられるが、 world が毎回異 なるので返り値が異なることがあるっていうこと? でもそれって一点集合な んでしょうか?
219 名前:デフォルトの名無しさん mailto:sage [04/10/14 17:26:23] 結合法則は分かったが *** Point(1): a * b /= b * a。順序は変えられない *** Point(2): x /= y ならば a' x と a' y は等しくなくてもよい Point(1)、(2)がIOの、順序を変えられない、毎回違う答えが帰るかもしれない という性質を満足させてくれます。 っていうのは普通の関数とどこが違うの? 普通の関数でもそういうのあるんだから、 モナドとかいわずに普通の関数と一緒に扱えばいいじゃない。
220 名前:デフォルトの名無しさん mailto:sage [04/10/14 17:33:16] x = yでもa' x と a' yは等しくなくてもいいんじゃない?
221 名前:デフォルトの名無しさん mailto:sage [04/10/14 17:50:24] 結合法則は満たすけど交換法則は満たさないって状況、 小学校でやる一般的な算数にある?
222 名前:デフォルトの名無しさん mailto:sage [04/10/14 17:52:51] 引き算、割り算
223 名前:デフォルトの名無しさん mailto:sage [04/10/14 18:00:53] 結合法則満たすのか?
224 名前:デフォルトの名無しさん mailto:sage [04/10/14 18:01:04] perl -e '$op="-"; print eval "4 $op (3 $op 2)"' perl -e '$op="-"; print eval "(4 $op 3) $op 2"' これ、答えが違っちゃうけど、、なんか間違ってます?
225 名前:デフォルトの名無しさん mailto:sage [04/10/14 18:16:35] >>219 > っていうのは普通の関数とどこが違うの? > 普通の関数でもそういうのあるんだから、 どこの世界の関数だそれは(w
226 名前:デフォルトの名無しさん mailto:sage [04/10/14 18:23:24] べき乗とかなら交換したら意味がちがうし x /= y ならば a' x と a' y は等しくないんちゃう?
227 名前:デフォルトの名無しさん mailto:sage [04/10/14 18:27:33] もちつけ。モノイドがモナドなわけじゃないぞ。 > この半群の集合への作用(注1)の仕方を定めたものがMonadです。
228 名前:デフォルトの名無しさん mailto:sage [04/10/14 18:29:58] >>219 逆で、関数でそういう性質が成り立って、文字列の連結や状態遷移でもそういう性質が成り立つからそれらを抽象化してモナドにしたってこと。 連結リストや配列リストの性質を抽象化してリストとして扱うようなのと同じ。
229 名前:デフォルトの名無しさん mailto:sage [04/10/14 18:31:50] じゃあ普通の関数もモナド?
230 名前:デフォルトの名無しさん mailto:sage [04/10/14 18:42:39] >>220 x = y で a' x = a' y でなくても構わないっていうのは数学的にはおかしい 気がしますが。 プログラム的には副作用が起きているなら成立すると思いますが、その副作用 を上手く扱うのがモナドなんじゃないの?
231 名前:デフォルトの名無しさん mailto:sage [04/10/14 18:54:09] 順序は正しく守って、毎回違った答えが出ても 処理系はエラーを出さず理論的にもきちんとまとめられるってことか?
232 名前:207 mailto:sage [04/10/14 19:02:54] >>218 そうですね。すみません。208は全然ダメです。 モナドをモノイドで押し切ろうというのは無理がありました。
233 名前:デフォルトの名無しさん mailto:sage [04/10/14 19:03:15] >>229 普通の関数だと、たとえば f(g(x), h(y)) がどの順番で評価されるかは不定。でも、モナドを使えば、その順序を確定さ せることができる。 ……副作用とかいう話じゃなくて、順序を確定させることが重要なのかなあ。 順序が確定的だから、副作用が起きるコードでもOKみたいな感じ?
234 名前:デフォルトの名無しさん mailto:sage [04/10/14 19:06:11] モナドってのは何をさすんだい? a * bだったらaやbがモナド?それとも*がモナド?
235 名前:207 mailto:sage [04/10/14 19:15:28] >>233 順序と、引数返り値に直接アクセスできないところが味噌です。 type IO a = world -> (a, world) なら、main world0 = let (s, world1) = getStr world0 in print s world0 とかやってしまえないようになるところ。 >>234 a, bと*の組みです。 行列群が、行列と行列のかけ算の両方がないと考えられないのと同様に。
236 名前:デフォルトの名無しさん mailto:sage [04/10/14 19:18:35] a,bはプログラム中の式 *は各式の関係を表す演算子
237 名前:207 mailto:sage [04/10/14 19:27:09] >>232 自己レスもちろん>>207 もだめです。 モナドは雰囲気はモノイドなんですがやっぱりモノイドとは みなせそうにないので、これも嘘です。 > この半群の集合への作用(注1)の仕方を定めたものがMonadです。 予想と違って、正しいかもしれないものだと素直に読んだ方が 多かったようで、申し訳ないです。
238 名前:デフォルトの名無しさん mailto:sage [04/10/14 19:31:13] 理解した部分だけ書くと、結合法則を満たす関数の合成を使うと IOのような実行の順序が重要な意味をもつ関数を(順序不定で)合成しても 合成された関数は一意的な順序でIOが実行される関数になるということか? 順序を保つ合成が結合法則を満たすのは分かったが、 結合法則を満たす合成は全て実行の順序を保つでいいのか?
239 名前:デフォルトの名無しさん mailto:sage [04/10/14 21:14:39] >>238 順序不定には合成できないから、明示的に順序をつけることを強制できる。 putStr (getLine, [getChar]) でなく getLine >>= (\s -> getChar >>= (\c -> putStr (s, [c]))) か getChar >>= (\c -> getLine >>= (\s -> putStr (s, [c])))
240 名前:デフォルトの名無しさん mailto:sage [04/10/14 21:26:54] じゃあモナドは実行の順序が決められてる関数の中の一つってことか?
241 名前:デフォルトの名無しさん mailto:sage [04/10/14 21:57:19] 例えば左から右へ順番に実行する関数hogeが定義できて、 hoge getLine getCharから getLine >>= (\s -> getChar >>= (\c -> putStr (s, [c])))と 同じ動作を定義できるのか?
242 名前:デフォルトの名無しさん mailto:sage [04/10/15 01:54:14] >結合法則を満たす合成は全て実行の順序を保つでいいのか? これは成り立たないと思う。 モナドの結合法則の概念と順序は本来関係ないんじゃないかな。 たまたま順序を組み立てるのにモナドが使えるってだけだと思う。 www.sampou.org/haskell/a-a-monads/html/introII.html ↑のListモナドとかは 順序とは関係なさそうだし。(関数から複数の遅延込みの非正格値を返すためのもの?) モナドの用途は順序の決定のみにあらずってとこか。
243 名前:デフォルトの名無しさん mailto:sage [04/10/15 04:12:02] >>241 hoge :: IO String -> IO Char -> IO () hoge f g = f >>= \s -> g >>= \c -> putStr (s, [c]) getLine :: String、getChar :: Char だったら無理。
244 名前:デフォルトの名無しさん mailto:sage [04/10/15 04:13:08] >>242 > List モナドは非決定性をもつ計算の連鎖を、演算をそれぞれのステップで可能なすべての値に適用することで、合成する戦略を内包しています。 だけなら、モナドでなくてもいいね。 ------------ module MList where data MList a = a :*: (MList a) | MNull deriving (Eq, Show) infixr 3 :*: instance {- Broken -} Monad MList where (x :*: xs) >>= f = merge (f x) (xs >>= f) where merge (x :*: xs) ys = x :*: merge ys xs merge MNull ys = ys MNull >>= f = MNull return x = x :*: MNull fail s = MNull toMList xs = foldr (:*:) MNull xs (>=>) = (>>=) -- 2ch : ">> が多すぎます!" (>=>) :: Monad m => m a -> (a -> m b) -> m b test f = test1 f == test2 f test1 f = f [1,2] >=> \x -> f [3, 4] >=> \y -> f [5, 6] test2 f = (f [1,2] >=> \x -> f [3, 4]) >=> \y -> f [5, 6]
245 名前:デフォルトの名無しさん mailto:sage [04/10/15 08:50:04] そうだよなあ。 モナドが「暗黙の引数world」と「関数のeagerな評価」を意味するだけなら,結合法則はなくてもよい。
246 名前:デフォルトの名無しさん mailto:sage [04/10/15 11:05:46] IOモナドについて。 話の流れから多少それるのかもしれませんが、 IOモナドの僕のとらえかたは以下のような感じです。 putStrはStringを引数としてとり、 「その文字列を表示する動作」を返す関数。 であり、putStr "Hello " >> putStr "World" とした場合、putStr "Hello "とputStr "World"のそれぞれが評価される 順番は問題ではない。 putStr "Hello "が評価された時点では、 "Hello "は出力されずに、「"Hello "を出力する動作」が 決定するだけである。 そして、putStr "Hello " >> putStr "World"は、 "Hello "を出力した後に"World"を出力する動作として評価される。 この時点では何の出力も生じない。 この動作は、main = ...というように、mainに代入されることにより、 評価器とは切り離された装置によって出力に変えられる。 つまり、putStr "Hello " >> (putStr "World" >> putStr "\n") とした場合、putStr "World >> putStr "\n"の部分が先に評価されて、 「"World"を出力した後に、"\n"を出力する動作」となり、 その後に、putStr "Hello "と結び付けられて、 「"Hello "を出力した後に「"World"を出力した後に"\n"を出力」する動作」 となる。 これは、 「「"Hello "を出力した後に"World"を出力」した後に"\n"を出力する動作」 と等しい。
247 名前:デフォルトの名無しさん mailto:sage [04/10/15 12:01:44] >>246 ありがとう、やっとすっきりした。 つまり継続を渡しているわけね。
248 名前:デフォルトの名無しさん mailto:sage [04/10/15 12:14:00] >>246 > であり、putStr "Hello " >> putStr "World" > とした場合、putStr "Hello "とputStr "World"のそれぞれが評価される > 順番は問題ではない。 順番は問題。これは左から評価しないと(されるように>>が定義されてないと)、 putStr "Hello ">> error "Error." 等が正しくうごかない。 > この動作は、main = ...というように、mainに代入されることにより、 > 評価器とは切り離された装置によって出力に変えられる。 上とも関連して、出力しながら内部の式を評価するわけで、 評価し終わったものを実行するのでは「ない」のだから、 main world を評価すると考えるほうがいいのでは。 上で自分でもただStateモナドのようにかいてしまったけれど、 IO a = World -> (a, World) {- ただしStrict -} と思うことにして。 (正則性と関連して実はIOはモナドの結合法則を満たしていなかったような) > つまり、putStr "Hello " >> (putStr "World" >> putStr "\n") > とした場合、putStr "World >> putStr "\n"の部分が先に評価されて、 ここも左から評価される。 あとは大体OKと思う。
249 名前:デフォルトの名無しさん mailto:sage [04/10/15 17:24:40] >>248 >順番は問題。 >>256 は > putStrはStringを引数としてとり、 >「その文字列を表示する動作」を返す関数。 という前提だからいいんじゃないの?
250 名前:デフォルトの名無しさん mailto:sage [04/10/15 18:08:50] >>249 putStr "Hello " >> error "Error." の右辺を先に評価したら"Hello"が表示される前にerrorで終わってしまうでしょ。 正格性解析かなにかで>>の左辺と右辺が Strictにしかも_|_にならずに評価できると知っていたら 何かの気まぐれで右辺から評価するかもしれないけど、基本は左から。 ちなみに右から(Lazyに)評価したら末尾再帰も無意味になるし無限ループも書けない。
251 名前:デフォルトの名無しさん mailto:sage [04/10/15 20:36:06] ちなみに右から(Lazyに)評価したら末尾再帰も無意味になるし無限ループも書けない。 どういう意味だ?