Programing in Haskell / Chapter.9 Excsise(2)
lifeゲームで画面がチカチカしないようにする。最近の更新頻度がやばい
-- タプルを受けっとって、lifeゲーム開始 life :: (Board , Board) -> IO () life (alive,die) = do { showcells alive die ; wait 5000 ; life (nextgen alive) } -- 生きているのはO,死んでるのは空白を出力する showcells :: Board -> Board -> IO () showcells alive die = do { seqn [writeat p " " | p <- die] ; seqn [writeat p "O" | p <- alive] } -- 死んだposのリストを返す dies :: Board -> [Pos] dies b = [p | p <- b, elem (liveneighbs b p) [1,4]]
Programing in Haskell / Chapter.9 Excsise(1)
一応、実装してみたものの。なんか違いが全然わからない…
今日は、なんだからダラダラしちゃった。ちょっと工夫して続きやろう。
> readLine :: IO String > readLine = readLineInteractive [] > where readLineInteractive xs = > do { c <- getChar > ; case (c, xs) of > ('\n' , xs) -> return (reverse xs) > ('\DEL', x:xs) -> do { putStr "\ESC[1D" > ; readLineInteractive xs > } > otherwise -> readLineInteractive (c:xs) > } > getLine' :: IO String > getLine' = do { x <- getChar > ; if x == '\n' then return [] > else do { xs <- getLine > ; return (x:xs) > } > }
Programing in Haskell / Chapter.9 Interactive Programs
http://www.amazon.co.jp/dp/0521692695 p.88-94
電卓を作るというところ。前の章で(>>=)を粘って考えたおかげで、今日の部分はかなりすっきり読めた。windowsでやってたんだけど、急遽linuxにPCを切り替えて、作業をすることに。
おもしろい定義がしてあるところがあって、Worldという型をつかってハードウェアの状態を説明する。
type IO = World -> World type IO a = World -> (a, World)
実際には、Curryを活用して、ハードウェアの状態を隠蔽するんだそうな。
-- type constructor newtype IO a -- constructors: IO :: ((a -> IOResult) -> IOResult) -> IO a -- instances: instance Functor IO instance Monad IO
ハードウェアの状態を記述するから、副作用とは無縁といえる?いえない?ちょっと曖昧です。
面白かったのはここ
IO ()
IO () is the type of actions that return the empty tuple as a dummy result value. Actions of latter type cat be thought of as purely side-effecting actions that return no result value ....
純粋に副作用のある命令ってw確かに、副作用があって、他にも値が返ってくると、わかりにくくなるものなのかなぁ。C言語の文字列取得とか、ポインタ渡しつつ返り値でエラーチェックとか考えるとたしかに一理あるのかもしれないですね!
またPHP Real Worldの翻訳するので今日はこのへんで!
Programing in Haskell / Chapter.8 Exercise (2)
Programing in Haskell(http://www.amazon.co.jp/dp/0521692695) P.85~86
Chapter8は、いつか読み直す。それなりに理解できたからOK
指数計算の部分は、名前をつける部分を見ようとしたら、カンニングしてしまった。。でも、そんなに難しくないと思われ
expr :: Parser Int expr = do t <- term do symbol "+" e <- expr return ( t + e ) +++ do symbol "-" e <- expr return ( t - e ) +++ return t term :: Parser Int term = do f <- factor do symbol "*" t <- term return (f * t) +++ do symbol "/" t <- term return ( f `div` t ) +++ return f factor :: Parser Int factor = do a <- atom do symbol "^" f <- factor return ( a ^ f ) +++ return a atom :: Parser Int atom = do symbol "(" e <- expr symbol ")" return e +++ natural eval :: String -> Int eval xs = case parse expr xs of [( n, [] )] -> n [(_, out )] -> error ("unused input " ++ out) [] -> error "invalid input"
Programing in Haskell / 8.10 Exercises(1)
Programing in Haskell(http://www.amazon.co.jp/dp/0521692695) P.85
問題1.2を解いた。パーサーについて勉強するのは、初めてなので、勉強になりますね!難しいところだと思うので、あせらずゆっくり解いていきます。
例によってソースコードは、サンプルコードを拡張した形になります。
どうやったらいいのか、まったくわからなかったので、とりあえず(-num)の形をパース刷る関数を作成して、もともとのnatと合成する感じです。
-- int :: Parser を定義せよ -- 自分の答え. ちょっと冗長だったか。 minus :: Parser Int minus = do x <- char '-' n <- many1 digit return ((-1) * (read n)) int' :: Parser Int int' = do x <- (nat +++ minus) return x -- 本の答え int :: Parser Int int = do char '-' n <- nat return (-n) +++ nat
お次は、コメントの定義。大御所のdoの書き方を真似てやってみました。これも結構時間がかかった。素直に書けばよかった!
-- comment::Parserを定義せよ comment :: Parser () comment = do { symbol "--" ; many (sat (/= '\n')) ; item ; return () }
コメントが定義できたときは、気持ちよかった!こういう抽象度の高いものをすぐ実装できたら、すごい気持ちいいだろうなぁ
Programing in Haskell / Chapter.8.4 Sequencing
Programing in Haskell(http://www.amazon.co.jp/dp/0521692695) P.74-77
どうしても、(>>=)で、パースしていくところがわからなかったので、細かくしらべた。
すごい参考になりました。ありがとうございます。
http://hippos-lab.com/blog/node/353
http://hippos-lab.com/blog/trackback/353(TrackBack)
こんなケースを考える。(>>=の定義はサンプルコードを探すとわかる)
parse item >>= (\x -> item >>= (\_ -> item >>= (\y -> return (x,y)))) "abcd"
とりあえずこんな風に置き換える.
item >>= (\x -> item >>= (\_ -> item >>= (\y -> return (x,y)))) "abcd" item >>= f(x) "abc"
この式の展開は以下のとおり
item >>= f(x) "abcd" <-> case parse item "abcd" of [] -> [] (['a', "bcd"]) -> parse f ('a') "bcd"
f(x)の内容を展開する
f('a') <-> item >>= g(_) "bcd" <-> case parse item ??? of [] -> [] [('b', "cd")] -> parse g ('b') "cd" -- 式の結果からこうなっているはずです!
- (parse item 'a')になったらエラーじゃないか!となっていたのですが、
定義ではf(x)に'a'が入っていただけで、それが(parse item inp)に適用されるとは書いていません。ここでで帰ってくるのは計算結果ではなく、手続き(クロージャ)が帰ってくるのですね!この結果、下は、inpの引数を求めて、手続きを返します。その隣にちょうどよく"bcd"が配置されているので、(\inp -> ...)が無事関数として実行されます。
(\inp -> ...) -- -> 手続きが帰ってくる -- こう解釈される (\inp -> ...) "bcd"
こうなれば、すっきりして解釈を進めることができますね!全体がどう解釈されていくのかを、haskellの文法ではありませんが書いてみました。
item >>= f(x) "abcd" <-> case parse item "abc" of [] -> [] (['a', "bc"]) -> parse f ('a') "bc" item >>= g(_) "bcd" -- \inpに"bcd"が適用 <-> case parse item of -- 手続きを返します [] -> [] [('b', "c")] -> parse g ('b') "c" item >>= h(y) "cd" <-> case parse item "c" of [] -> [] [('c', "")] -> return ('a', 'c')
引数に突っ込んでいた'a'は、returnの時に返されることになります。returnも引数を二つとるので、値そのものを返すのではなく、手続きを返すことになります。
(\inp -> ... return (x, y) ) "d" -- -> ([('a', 'c') , 'd'])
うーむ。奥が深いですね。明日は、残りと演習問題いってみよう!ちょっとここら辺から自分の未開拓領域に入っていくので、ペースが遅くなりそうです。でも、わかったときはいいね!
Programing in Haskell / Chapter.8
見たこともない予約語がサンプルコードにあった。明日はこれを解明しよう。