2008-09-25
■ 夏目漱石の「こころ」を行単位でシャッフルしたい2 
この main も bind >>= を使って一行で書こうとしましたが、どうするのかまだよくわかりません。
夏目漱石の「こころ」を行単位でシャッフルしたい
と以前の記事で書きましたが、掲示板に liftM 関数を使った書き方の話を見つけたので、それを参考に書き直してみました。
前に書いたコード(shuffle.hs)は、
import Data.List import Data.Ord import Random shuffle g = snd . unzip . sortBy (comparing fst) . zip (randoms g :: [Int]) putShuffleLines g = putStr . unlines . shuffle g . lines main = do g <- newStdGen s <- getContents putShuffleLines g s
でしたが、この putShuffleLines と main は Control.Monad の liftM2 を使って
import Control.Monad import Data.List import Data.Ord import Random shuffle g = snd . unzip . sortBy (comparing fst) . zip (randoms g :: [Int]) shuffleLines g = unlines . shuffle g . lines main = liftM2 shuffleLines newStdGen getContents >>= putStr
と書き直すことができるらしく、以前と同様に
ghc shuffle.hs
main < kokoro.txt
動きました。
以下に参考にした会話を引用します。
766 デフォルトの名無しさん 2008/09/24(水) 15:23:46
do構文で、変数の使用が強制されるのはなんとかならんの?
.とか$とかの気の利いたバージョンない?
767 デフォルトの名無しさん sage 2008/09/24(水) 15:27:56
何を言ってるのかよく分からんが >>= とか?
768 デフォルトの名無しさん sage 2008/09/24(水) 15:36:59
>>=だけですっきりいけるならdo構文使わないでしょ(ってこともないか?少なくとも俺は)。
do構文でモナドを「外す」ためだけに一時変数がやたら必要になるのがイヤって話。
つまるところ>>=になっちまいそうな気もするけど、
便利な演算子なり特殊なカッコなりで、無駄な変数使わずに何とかならんかなぁ、と。
769 デフォルトの名無しさん sage 2008/09/24(水) 16:11:24
なにか具体例見せてくれ
770 デフォルトの名無しさん sage 2008/09/24(水) 16:18:02
do式の中で、
a <- v
b <- f a
は、aを使わずに
b <- v >>= f
と書ける
同様に、
a <- v
let b = f a
は、
b <- liftM f v
と書ける
こういう話?
>>=は普通にdo構文の内部で使えるよ
俺はこの場合=<<を使う方が好きだけど
771 デフォルトの名無しさん sage 2008/09/24(水) 16:26:30
何を言ってるのか俺もよく分からん。
do ...; a <- m; f a; ...
を
do ...; f =<< m; ... -- m >>= f でも同じだけど...
とか
do ...; a <- m; let b = f a; ...; g b; ...; h b; ...
を
do ...; b <- liftM f m; ...; g b; ...; h b; ...
とかすればいいって話じゃなくて?
って書き込もうとしたんだけどその前に新着レス見たら>>770被りすぎ。
772 デフォルトの名無しさん sage 2008/09/24(水) 16:44:57
n <- m
a <- n
を
a <- join m
にするパターンもあるかも。
n <- m
o <- n
a <- o
を
a <- join (join m)
とか。
773 デフォルトの名無しさん sage 2008/09/24(水) 16:48:50
ぱっといい例は書けないけど、例えば単純な例で
do args <- getArgs
cnt <- getContents
now <- getClockTime
return someFunc args cnt now
を、
do return soumeFunc #getArgs #getContents #getClockTime
とかこんな感じに書けないかと。(#が架空のモナド外し演算子とか)
774 デフォルトの名無しさん sage 2008/09/24(水) 16:53:15
>>770,771,772
ありがとう。特にjoinは使った事なかった。
俺がアホでした。
775 デフォルトの名無しさん sage 2008/09/24(水) 16:56:54
あれ?やっぱ違うや。求めてるのとjoin。いや、それはそれで勉強になったけど。
776 デフォルトの名無しさん sage 2008/09/24(水) 17:01:37
というか、liftM3ですね。とりあえず釣って来ます。
777 デフォルトの名無しさん sage 2008/09/24(水) 17:21:21
ちなみに、
do args <- getArgs
cnt <- getContents
return otherFunc args True cnt
だったら?
778 デフォルトの名無しさん sage 2008/09/24(水) 17:27:31
>>773みたいな構文は俺も欲しい
このスレで前に同じことを書いた記憶がある
Template Haskellを使えばなんとかなるかな
>>777
liftM3 otherFunc getArgs (return True) getContents
不恰好だけど
779 デフォルトの名無しさん sage 2008/09/24(水) 18:03:09
>>773 は Control.Applicative を使って
soumeFunc <$> getArgs <*> getContents <*> getClockTime
や
return sumFunc <*> getArgs <*> getContents <*> getClockTime
って書ける。infixl 4 # ; (#)=(<*>) とすればあのままいける。
っていうのは
(return soumeFunc) #getArgs #getContents #getClockTime
じゃなくて
return (soumeFunc #getArgs #getContents #getClockTime)
のつもりだろうから嘘だけど。
ただ、IO は Applicative のインスタンスになってるけど、
一般のモナドは WrappedMonad って型が用意されてるだけなので、ちょっと面倒。
でも Control.Monad に <*> と同じ意味の ap ってのがあってこれはどのモナドにも使える。
<$> とかの Control.Applicative にあるいろいろな関数がないけど。
あと Control.Applicative には f (a -> b) -> a -> f b な関数が無いけど
それを f *$ x = f <*> pure x とか定義すれば
liftM3 otherFunc getArgs (return True) getContents は
otherFunc <$> getArgs *$ True <*> getContents と書ける。さすがにキモイ。
780 デフォルトの名無しさん sage 2008/09/24(水) 18:18:11
おおっ、あるのね。
俺の見る程度の範囲じゃ<*>とかはあんま見ないけど、そういえばapは見るな。
まあ、>>698とか見ると、>>778の書き方が普通は落とし所って所かも知れんけど、調べてみます。
関数型プログラミング言語Haskell Part9