関数型プログラミング言語Haskell Part3
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
NGNGhttp://www.haskell.org/
日本語サイト
http://www.sampou.org/cgi-bin/haskell.cgi
Http://www.teu.ac.jp/kougi/koshida/Prog6/index.html
過去ログ、関連スレは>>2-5
0175デフォルトの名無しさん
NGNGこんなもんでどうでしょうか。
0176デフォルトの名無しさん
NGNG[a->b]->[a]->[b]かな?
0177デフォルトの名無しさん
NGNG0178デフォルトの名無しさん
NGNG[5,7,9]
ナルホド。
0179デフォルトの名無しさん
NGNGそれとも( )じゃワケがわからないから($)と書けるように
目に見える演算子として用意されているだけ?
0180デフォルトの名無しさん
NGNG0181145
NGNG>>179 何も代わらない。関数適用のための演算子だから。
本来の利用法は >>178 みたいなものなのかな(個々の要素にそれぞれ適用する
ためには、関数適用の演算子があると便利)。
f $ g x と書くと、演算子の優先度の関係上 f(g x) と同じことになるので便
利、ついでに結合性の関係で f $ g $ h x とか書ける、というのが個人的に
は嬉しい。カッコの省略にも使える。
関数合成はあくまで関数の合成の演算子なので、 f . g . h x とは書けない。
(f . g . h) x なら書けるけど。
0182デフォルトの名無しさん
NGNGFunctional 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
に載っているので興味があるひとは読んでみるべし。
0183デフォルトの名無しさん
NGNG> 只の関数適用(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なんかをつかっていると結構引っかかる。
0184デフォルトの名無しさん
NGNGinfixl 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の間違い。
0185デフォルトの名無しさん
NGNG型指定が要った。
ncat 'a' 'b' 'c' :: String
0186デフォルトの名無しさん
NGNG0187デフォルトの名無しさん
NGNG0188デフォルトの名無しさん
NGNG0189デフォルトの名無しさん
NGNG0190デフォルトの名無しさん
NGNG「そのうち出る」 = 「そのうち出版される」という意味か。
「テキストの候補に挙がる」ではなく。
0191デフォルトの名無しさん
NGNG0192デフォルトの名無しさん
NGNG近刊とあってまだ出てないようだ。
ttp://www.kyoto-su.ac.jp/~hxm/hxm.cc/research.ja.html
0193デフォルトの名無しさん
NGNG(length (hoge xx yy zz)) < 3
とかで困る。かも。
0194デフォルトの名無しさん
NGNG> 末尾再起すると、遅延評価されないですね。
そんなことはない。
> (length (hoge xx yy zz)) < 3
> とかで困る。かも。
lengthがstrictだからhogeがlazyでも意味がないとはいえるが、
末尾再帰とは無関係なので、意味がわからない。
なにを誤解してるのですか?
0195デフォルトの名無しさん
NGNG『末尾再帰の最適化』をすると遅延評価できない(或いはその逆)、のことを言いたいのかな。
それだったら解る。
あ、でも例 (length (hoge xx yy zz)) < 3 の意味はやっぱりわからない。
0196デフォルトの名無しさん
NGNG> 『末尾再帰の最適化』をすると遅延評価できない(或いはその逆)、のことを言いたいのかな。
詳しく説明きぼんぬ。
gotoでジャンプするコードにするとサンクが作れないのかな?
0197デフォルトの名無しさん
NGNGtake n 末尾再帰関数(無限リスト)
みたいなのが出来ないということでは?
0198197
NGNGtake n (末尾再帰関数 無限リスト ・・)
です。
0199193(初心者)
NGNG>197さんの言うとおりです。
例は適当にかいたらだめでした。
0200デフォルトの名無しさん
NGNGなにができないと?
take' 0 xs = xs
take' n (x:xs) = take' (n - 1) xs
take n (take' 10 [0..])
0201197
NGNG返値も無限リストの場合です。
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..])
0202デフォルトの名無しさん
NGNGnub0 [1..]自体がbottom(無限リストではない)なんだから
末尾再帰も糞もないですよ。
nub0' :: [Int] -> Int
nub0' = foldr (+) 0
だって同じこと。
0203197
NGNGnub0 を末尾再帰で定義したから、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..] は無限リストになる、という意味です。
0204デフォルトの名無しさん
NGNG関数型言語のキモは副作用とのコラボレーションなんだし
0206デフォルトの名無しさん
NGNGモナドは数学上はモノイドといって単位元を持つ半群のこと。
一応簡単な説明。
(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
0207デフォルトの名無しさん
NGNGMonoidだと思って話すなら:
結合法則: (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 等)をどこにうつすかを決めることは同じことだからです。
続く。
0208207
NGNG*** 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)はどちらも数学の概念で、似ていますが別物です。
0209デフォルトの名無しさん
NGNGの()の意味はなんだ?
単に型が合うかどうかか?演算の時間的な順番か?
0210デフォルトの名無しさん
NGNG演算の順序。
代数の本を読めばどしょっぱなに書いてあるよ。
0211デフォルトの名無しさん
NGNG最初に出力してくれるのかい?
0212デフォルトの名無しさん
NGNGCで {{f(); g();} h();} と {f(); {g(); h();}} が同じ結果になる
みたいなものだ。
0213デフォルトの名無しさん
NGNG0214デフォルトの名無しさん
NGNGモノイドの説明だとしたら、その式はそうとしか言えないのでは。整数上の加
算について考えると、
(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 の方に書いてあると思うんだが、こっちはよくわからない……。
0215デフォルトの名無しさん
NGNG> 「結合則は成立するが、交換則は成立していない」
「交換則は必ずしも成立するわけではない」のほうが適当では?
0216デフォルトの名無しさん
NGNGどういう風に括弧をつけても関数Xの適用順序は
左から右、右から左と一定であるって意味でいいの?
0217デフォルトの名無しさん
NGNGああその通りですね。失礼しました。
>>213=216
まあその通りといえばその通りではないかと思います。
*を関数の合成みたいな演算だと考えればよいのでは。
0218デフォルトの名無しさん
NGNG> *** Point(2): x /= y ならば a' x と a' y は等しくなくてもよい
はわかるとして、 GetLine :: U -> IO String であり、 U が一点集合なのだ
としたら、これは x = y である(にもかかわらず a' x /= a' y になりうる)
例のように読めてしまったのですが、どこで間違えているんでしょうか?
getLine' world というのは、常に world が与えられるが、 world が毎回異
なるので返り値が異なることがあるっていうこと? でもそれって一点集合な
んでしょうか?
0219デフォルトの名無しさん
NGNG*** Point(1): a * b /= b * a。順序は変えられない
*** Point(2): x /= y ならば a' x と a' y は等しくなくてもよい
Point(1)、(2)がIOの、順序を変えられない、毎回違う答えが帰るかもしれない
という性質を満足させてくれます。
っていうのは普通の関数とどこが違うの?
普通の関数でもそういうのあるんだから、
モナドとかいわずに普通の関数と一緒に扱えばいいじゃない。
0220デフォルトの名無しさん
NGNG0221デフォルトの名無しさん
NGNG小学校でやる一般的な算数にある?
0222デフォルトの名無しさん
NGNG0223デフォルトの名無しさん
NGNG0224デフォルトの名無しさん
NGNGperl -e '$op="-"; print eval "(4 $op 3) $op 2"'
これ、答えが違っちゃうけど、、なんか間違ってます?
0225デフォルトの名無しさん
NGNG> っていうのは普通の関数とどこが違うの?
> 普通の関数でもそういうのあるんだから、
どこの世界の関数だそれは(w
0226デフォルトの名無しさん
NGNGx /= y ならば a' x と a' y は等しくないんちゃう?
0227デフォルトの名無しさん
NGNG> この半群の集合への作用(注1)の仕方を定めたものがMonadです。
0228デフォルトの名無しさん
NGNG逆で、関数でそういう性質が成り立って、文字列の連結や状態遷移でもそういう性質が成り立つからそれらを抽象化してモナドにしたってこと。
連結リストや配列リストの性質を抽象化してリストとして扱うようなのと同じ。
0229デフォルトの名無しさん
NGNG0230デフォルトの名無しさん
NGNGx = y で a' x = a' y でなくても構わないっていうのは数学的にはおかしい
気がしますが。
プログラム的には副作用が起きているなら成立すると思いますが、その副作用
を上手く扱うのがモナドなんじゃないの?
0231デフォルトの名無しさん
NGNG処理系はエラーを出さず理論的にもきちんとまとめられるってことか?
0233デフォルトの名無しさん
NGNG普通の関数だと、たとえば
f(g(x), h(y))
がどの順番で評価されるかは不定。でも、モナドを使えば、その順序を確定さ
せることができる。
……副作用とかいう話じゃなくて、順序を確定させることが重要なのかなあ。
順序が確定的だから、副作用が起きるコードでもOKみたいな感じ?
0234デフォルトの名無しさん
NGNGa * bだったらaやbがモナド?それとも*がモナド?
0235207
NGNG順序と、引数返り値に直接アクセスできないところが味噌です。
type IO a = world -> (a, world)
なら、main world0 = let (s, world1) = getStr world0 in print s world0
とかやってしまえないようになるところ。
>>234
a, bと*の組みです。
行列群が、行列と行列のかけ算の両方がないと考えられないのと同様に。
0236デフォルトの名無しさん
NGNG*は各式の関係を表す演算子
0237207
NGNGモナドは雰囲気はモノイドなんですがやっぱりモノイドとは
みなせそうにないので、これも嘘です。
> この半群の集合への作用(注1)の仕方を定めたものがMonadです。
予想と違って、正しいかもしれないものだと素直に読んだ方が
多かったようで、申し訳ないです。
0238デフォルトの名無しさん
NGNGIOのような実行の順序が重要な意味をもつ関数を(順序不定で)合成しても
合成された関数は一意的な順序でIOが実行される関数になるということか?
順序を保つ合成が結合法則を満たすのは分かったが、
結合法則を満たす合成は全て実行の順序を保つでいいのか?
0239デフォルトの名無しさん
NGNG順序不定には合成できないから、明示的に順序をつけることを強制できる。
putStr (getLine, [getChar])
でなく
getLine >>= (\s -> getChar >>= (\c -> putStr (s, [c])))
か
getChar >>= (\c -> getLine >>= (\s -> putStr (s, [c])))
0240デフォルトの名無しさん
NGNG0241デフォルトの名無しさん
NGNGhoge getLine getCharから
getLine >>= (\s -> getChar >>= (\c -> putStr (s, [c])))と
同じ動作を定義できるのか?
0242デフォルトの名無しさん
NGNGこれは成り立たないと思う。
モナドの結合法則の概念と順序は本来関係ないんじゃないかな。
たまたま順序を組み立てるのにモナドが使えるってだけだと思う。
http://www.sampou.org/haskell/a-a-monads/html/introII.html
↑のListモナドとかは
順序とは関係なさそうだし。(関数から複数の遅延込みの非正格値を返すためのもの?)
モナドの用途は順序の決定のみにあらずってとこか。
0243デフォルトの名無しさん
NGNGhoge :: IO String -> IO Char -> IO ()
hoge f g = f >>= \s -> g >>= \c -> putStr (s, [c])
getLine :: String、getChar :: Char だったら無理。
0244デフォルトの名無しさん
NGNG> 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]
0245デフォルトの名無しさん
NGNGモナドが「暗黙の引数world」と「関数のeagerな評価」を意味するだけなら,結合法則はなくてもよい。
0246デフォルトの名無しさん
NGNG話の流れから多少それるのかもしれませんが、
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"を出力する動作」
と等しい。
0247デフォルトの名無しさん
NGNGありがとう、やっとすっきりした。
つまり継続を渡しているわけね。
0248デフォルトの名無しさん
NGNG> であり、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と思う。
0249デフォルトの名無しさん
NGNG>順番は問題。
>>256は
> putStrはStringを引数としてとり、
>「その文字列を表示する動作」を返す関数。
という前提だからいいんじゃないの?
0250デフォルトの名無しさん
NGNGputStr "Hello " >> error "Error."
の右辺を先に評価したら"Hello"が表示される前にerrorで終わってしまうでしょ。
正格性解析かなにかで>>の左辺と右辺が
Strictにしかも_|_にならずに評価できると知っていたら
何かの気まぐれで右辺から評価するかもしれないけど、基本は左から。
ちなみに右から(Lazyに)評価したら末尾再帰も無意味になるし無限ループも書けない。
0251デフォルトの名無しさん
NGNGどういう意味だ?
0252246
NGNGputStr "Hello " >> putStr "World"は、
"Hello "を出力する動作の後に、"World"を出力する動作を続けた動作と解釈される。
と言いかえるべきなのかな。
(1+3) : []を、(4ではなく)1+3を空のリストに加えたものと解釈される。
というのと同じで、この1+3が4になるのはmainに関連づけられたとき
(とhugsなどで、返り値の表示を求められたとき)のみである。
つまり、putStr "Hello " >> putStr "World"が左から評価されるのは、
print ((1+2):(2+3):[])が左から評価されるのと同様、
値が必要になった時点で評価されるという、遅延評価の性質から理解できる。
print ((1+2):(2+3):[])でまず1+2が、つぎに2+3が評価されるのは、
(:)に左から順に評価するという性質があるのではなく、
必要とされるのが1+2のほうが先であるというためである。
これは、print $ reverse ((1+2):error "foo":(2+3):[])の出力が[5,となる点からも確認できる。
それと同様にputStr "Hello " >> putStr "World"が左から評価されるのは、
まずputStr "Hello "がプログラムの実行に必要とされ、その後にputStr "World"が必要とされるためであり、
(>>)が左から評価されるといった性質を持っている必要はない。
(しかし、(>>)の右側が左側よりも先に必要とされるという状況は考えられないので(>>)が左から評価される性質を持つというのは
そんなに間違いではないかもしれない。)
putStr "Hello " >> error "Error."がうまく評価されるのも同様で、
"Hello "の出力の際にはerror "Error."を評価する必要がないためである。
現時点での僕の解釈ですので、間違いもあると思います。
Haskellに積まれた概念は非常に興味深いので、
今後も熟考していこうと思っています。
0253デフォルトの名無しさん
NGNGモナドの表示的意味は言語仕様に書いてないのか?
[| >> |]ρσ = ...?
0254デフォルトの名無しさん
NGNGいったいどういう原理によって
> まずputStr "Hello "がプログラムの実行に必要とされ、その後にputStr "World"が必要とされるためであり、
こうなってると思ってるわけですか?
mainや(>>)は関数じゃなくてなにかすごく賢い"評価器とは切り離された装置"
が何が必要かを見切って必要なところだけ評価するという立場?
それならそれでもいいですが…
私は、State(World)についてStrictなMonadだと思えば、
なぜ(>>)の左が先に必要になったのかが、説明できると書いたわけです。
0255デフォルトの名無しさん
NGNGまず、mainだけ特殊な評価をうけるとは考えないことにします。
右から評価されると無限ループも書けないというのは、
main = loop where loop = act >> loop
act = print "x"
ここでloopの右辺を先に評価したらact >> (act >> (act >> ..))と
ネストした列ができるだけでloopの処理が進まないという意味です。
末尾再帰も同様のことになります。
先に述べたように、特殊な評価装置や特殊ルールは考えないので、これは、
(>>)がそういう順序に評価を導くように定義されているということを意味します。
単にmainそのものを評価しても、(\_ -> ...)の形か、
(コンストラクタ) ...の形になって...の部分は評価されずに終わります。
これでは...の中に書いてあるIOアクションの列をどう評価、
実行していけばいいかはわかりません。
そこで、mainは関数であって(type IO a = World -> (a, World)、
プログラムの実行とはmain worldを評価する、つまりmain worldの
返り値を求める評価を行うことだと考えることにします。
例えば(putStr "X") worldを評価すると、
"X"が出力されたWorldを返します("X"が出力される)。
0256デフォルトの名無しさん
NGNGいいので、まず返り値に必要な部分から計算されます。
したがって、遅延評価ならば、a >> bにおいてworldに最後に関与する
「外側」にある"b"のほうから評価が行われるはずだということになります。
これが「右から(Lazyに)」の意味です。
ちろんこれではループも書けないのでIOモナドとしては使えません。
しかし、WorldについてStrictなモナドだとすれば、
左から評価されるようになります。
-- typeではモナドの定義がHaskell98では書けない。
newtype IO a = IO { runIO :: World -> (a, World) }
instance Monad IO where
ioact >>= f = IO $ \world -> world `seq`
let (a, world') = runIO ioact world
in runIO (f a) $! world'
もしよくわからなければ、Control.Monad.Stateのlazyなstateモナドで
loopや末尾再帰のプログラムを書いて挙動を観察してみてください。
0257デフォルトの名無しさん
NGNGhttp://www.haskell.org/definition/haskell98-report.pdf
0258デフォルトの名無しさん
NGNG基づいてないと?
IOの話なら、規格の性質を満たすIOはいかにして定義され得るか
ということを議論しているつもりなんだけど…
0259もなど初心者
NGNGデバッグ辛くないですか?
0260デフォルトの名無しさん
NGNG0261デフォルトの名無しさん
NGNGThe >>= operation passes the result of the first operation as an argument to the second operation.
ということなので,f >>= gに対して,fの中で起こる副作用がgの中で起こる副作用より先に起こる
ようにするには,
(1) >>=は,左辺の引数についてstrict
(2) g(正確にはgの中での副作用の呼び出し)がstrict
のどちらでもよい(ように思える).
0262デフォルトの名無しさん
NGNG> どちらの方法でもIOモナドの外部仕様を満たせるんじゃない?
だれが(1)を主張しているの?
> (1) >>=は,左辺の引数についてstrict
f >>= g のfが先に評価されるだけで、actionの実行とは関係ない。
例えば、f >> (g >> (h >> ..)) の無限列ができるだけでactionが実行されない
こともあり得る。
> (2) g(正確にはgの中での副作用の呼び出し)がstrict
なにがいいたいのかよくわからない。
Monadの話をしているのだから>>=の性質について話さないと。
>>255-256理論のことなのかな(そうは読めないけれど)。
それから、IOモナドはこれ
> Special operations (methods in the class Monad, see Section 6.3.6)
> sequentially compose actions,
> corresponding to sequencing operators (such as the semicolon) in imperative languages.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
を要求してるからf >>= gのfが先に評価されるのであって、
>>261の部分からはそうなるとは限らないことに注意。(cf. LazyなStateモナド)
0263デフォルトの名無しさん
NGNGMLのように表示意味論(操作意味論でもいいけど)でformalに定義
されてるんじゃないの?
色々と仕様の背後にある意図を考えるのもいいけど、まずちゃんとした定義
を出してくれると素人には有難いなあ。言葉の定義も人によって違うみたいだし。
ちなみに
fがstrict <=> f(_|_) = _|_
lazy evaluation <=> λ計算でいうところのnormal reduction
ということでいいの?
0264デフォルトの名無しさん
NGNG> MLのように表示意味論(操作意味論でもいいけど)でformalに定義
IOはどうなんだろ?
http://citeseer.ist.psu.edu/peytonjones93imperative.html
# 個人的にはHaskellのコミュニティはそういう文化じゃないと思ってる。
# formalなsemanticsがどうとかで論文書くんじゃなくて、
# 新しい便利なアイディアをどんどん導入して実際に使う。
# informalなsemanticsだけど気にしない、みたいなことがよく書いてあるきがする。
#
# そういうことに興味がないことによる偏見かもしれない。
ググッたらちょっと古い(1996)けどこんなのも
http://www-fp.dcs.st-and.ac.uk/~kh/papers/io-tutorial/section3_7.html
> No formal semantics for these I/O primitives is possible at present,
> because there is no complete formal semantics for Haskell itself.
formalでないと理解した気がしないなら、
Concurrent Haskell (Simon PJ他)の論文でIOのsemanticsは誰かの論文を参照、
みたいなことが書いてあった気がするから、探してみたら。
> fがstrict <=> f(_|_) = _|_
> lazy evaluation <=> λ計算でいうところのnormal reduction
いいんじゃない。ちなみにdataコンストラクタはlifted。
0265デフォルトの名無しさん
NGNG0266デフォルトの名無しさん
NGNG等しくはないね。
でもλ計算でいうところのnormal-order reductionをするわけでしょう?
0267デフォルトの名無しさん
NGNGSimon Peyton Jones, Andrew Gordon and Sigbjorn Finne. Concurrent Haskell, POPL, 1996.
をざっと見たところ、その辺の詳しい話は
Roy L. Crole and Andrew D. Gordon.
A Sound Metalogical Semantics for Input/Output Effects, CSL, 1994.
Andrew D. Gordon.
Functional Programming and Input/Output, Cambridge University Press, 1994.
を参照と書いてあった。暇なときにみてみよう。
ちなみに"Concurrent Haskell"の論文も結構面白い。IOの話については
下のような記述があった。ご参考…といってもここの人には常識か。
The sequencing combinators, >> and >>=, feed the result state
of their left hand argument to the input of their right hand
argument, thereby forcing the two actions (via the data
dependency) to be performed in the correct order.
...
In principle, then, a program is just a state transformer
that is applied to the real world to give a new world.
In practice, however, it is crucial that the side-effects
the program specifies are performed incrementally, and
not all at once when the program finishes. A state-transformer
semantics for I/O is therefore, alas, unsatisfactory, and
becomes untenable when concurrency is introduced, a matter to
which we return in Section 6.
0268Haskell???なにそれ?食えるの?
NGNGhttp://pc5.2ch.net/test/read.cgi/tech/1092932484/494-
おい。
Rubyにケチ付けてるこの馬鹿引き取ってくれよ。
0269デフォルトの名無しさん
NGNG0271デフォルトの名無しさん
NGNGnormal reduction = leftmost reduction = lazy reduction
じゃなかったっけ
0272デフォルトの名無しさん
NGNGlazy evaluation と call-by-need が対応して
normal-order reduction というと call-by-name が対応するといいたいんじゃない?
0273デフォルトの名無しさん
NGNG> なにかすごく賢い"評価器とは切り離された装置"
が必要性を判断してくれると仮定しなければ、
print $ [3, 1+2, 4] !! 0
で1+2が評価されない理由は説明できないと思う。
具体的にはその装置はHaskellの一部であって、
Haskellプログラムの内側では議論できない実装に近い部分の話になって
くるんじゃないかな。
>>255,>>256のような議論は有意義だと思うが、
上述したような「装置」によって、(:)と(>>)を同列に扱えるのであり、
(:)にその「装置」が必要とされている以上、
(>>)に他の特別な理論をあてはめるよりは、
必要に応じて評価される。という
lazy evaluationの原則を単純にあてはめればすむのではないかと思う。
ちなみに、
IOというものは[](リスト)と同様にそこにある何かであり、
たとえばputStrLn "Hello"が実行されると"Hello"を出力するのは、
[1,2,3]が(!!1)で2を返すのと同様にとらえられるのではないだろうか。
IOは評価時点では出力されずに、実行という次のステップで出力が生じる。
これは、
main = putStr "Hello " `seq` putStrLn "World"
での出力が
World
であるという点からも理解されるのではないだろうか。
HaskellのIOでは評価と実行は切り離されている。ということに今日気付いた。
0274デフォルトの名無しさん
NGNG■ このスレッドは過去ログ倉庫に格納されています