今回は、12章をもう一度読みました。前回、いまひとつ内容を把握しきれなかった12章でしたが、もう一度読み直してみると、意外と読めることに気づきました。何回も読むとだんだん理解しやすくなるものですね。
12.1 簡単なサーバ
セクション 12.1 の最後に、いくつか読者への課題が出てきました。
Ctrl+C
でサーバに中断をかけたら? 非同期例外によりメインスレッドが終了。非同期例外は9章で出てきた。テキスト行がパースできなかったら? 同期例外により talk スレッドが終了。同期例外は8章で出てきた。こういうのが出てくると、前の章でやったことの積み重ねだな、と感じます。
また、Haskell でログを記録するってどうするんだっけ、と一瞬思いました。しかし、IO の中だったら普通に printf
で標準出力に出力したり、appendFile
でファイルに出力したりできるのでした。
このサーバ、数字を送らないと勝手に接続が閉じられてしまうのはちょっとつらいです。特に、改行のみを送っただけでも切断される。そのへんの改善は課題として良さそうです。
12.2 単純なサーバの状態による拡張
セクション 12.2 の最後にも、いくつか読者への課題が出てきました。
この server2 で、各クライアントが共有する係数値の扱いには注意が必要です。今回の読書会でのハマりどころでした。
実は、係数変更のコマンドで数値にパースできない不正な値を渡すと、とんでもないことが起こります。コマンドを送ったクライアントが切断されるだけでなく、それ以外のクライアントも切断され、その後は新規クライアントも接続できなくなります。
未評価のまま TVar
に書き込むと、すべての読み出し側で評価が行われて例外を引き起こしてしまいます。Haskell の遅延評価をちゃんと頭に入れておかないと痛い目にあうパターン。
writeTVar factor (read s :: Integer) で factor に入るのは (read s :: Integer) が未評価の状態で入るので、このタイミングでは落ちない。 #umekitahs
— いせ (@iseebi) 2016年4月13日
その後、送信したものも含めてすべてのスレッドで f' <- readTVar factor した後、if (f /= f') のところで (read s :: Integer) が評価されて落ちてしまう #umekitahs
— いせ (@iseebi) 2016年4月13日
新規で接続したクライアントも (read s :: Integer) を評価するので、二度とつながらなくなってしまう。writeTVar のところで seq しておけば、その場で評価されるので、影響をうけるのは送ったやつだけ #umekitahs
— いせ (@iseebi) 2016年4月13日
あと面倒なのが、処理を追いかけようと思って printf
を挿入したときに、printf
に値を渡すことでその場で評価してしまうという点。このため、printf
を入れると挙動が変わる、という現象が簡単に起こります。printf
デバッグには注意が必要。
次回
次回は13章を読みます。あと数回で終わりそう。次にやることをそろそろ考えないといけない。