LoginSignup
4
4

More than 5 years have passed since last update.

Haskell でシグナルで中断された時にクリーンナップ処理をしてから終了する

Posted at

最近 Programming in Haskell という本を読んでいるのですが 9.7 Game of Life(ターミナルに Game of Life をアニメーション表示)を動かしてみたらカーソルが邪魔だったので、プログラムの開始時にカーソルを消して終了時にまた表示するようにしようとしました。

import System.Process (system)

main :: IO ()
main = do
  -- カーソルを隠す
  system "tput civis"
  -- Game of Life を画面に表示
  life glider
  -- カーソルを表示(ここに到達しない!!!)
  system "tput cvvis"
  return ()

life :: Board -> IO ()
glider :: Board

しかし life が無限ループで Game of Life を表示するため、カーソルを表示するところまで到達しません。Ctrl+C で中断するとカーソルが隠れたままになってしまいます。

unix - Killing a Haskell binary - Stack Overflow を参考にして、シグナルで中断されるまで a -> IO a な処理をループさせる関数を書いてみました。MVar で中断されたかどうかを管理し、中断されていた場合はループを止めます。

import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, tryTakeMVar)
import System.Posix.Signals (Handler, Handler(CatchOnce), installHandler, sigINT, sigTERM)

loopUntilInterruption :: (a -> IO a) -> a -> IO ()
loopUntilInterruption p init = do
  v <- newEmptyMVar
  installHandler sigINT (handler v) Nothing
  installHandler sigTERM (handler v) Nothing
  loop v p init

handler :: MVar () -> Handler
handler v = CatchOnce $ putMVar v ()

loop :: MVar () -> (a -> IO a) -> a -> IO ()
loop v p prev = do
  x <- p prev
  val <- tryTakeMVar v
  case val of
    Just _ -> return ()
    Nothing -> loop v p x >> return ()

Game of Life の例では life の型を変えて前回の結果を返すようにして、loopUntilInterruption でループさせました。今度はシグナルで中断しても終了処理が呼ばれます。

import System.Process (system)

main :: IO ()
main = do
  -- カーソルを隠す
  system "tput civis"
  -- 中断されるまでループ
  loopUntilInterruption life glider
  -- カーソルを表示(今度は呼ばれる!!!)
  system "tput cvvis"
  return ()

life :: Board -> IO Board
glider :: Board

めでたし、めでたし。

ちなみに Programming in HaskelledX の Introduction to Functinal Programming で Erik Meijer がおすすめしていたので読んでいます。約 150 ページと薄いのに内容が凝縮されていていい感じです。Monad などについてもごちゃごちゃ言わないので、個人的にはすごい Haskell たのしく学ぼう!よりもわかりやすいと思いました。日本語版の方が安いのでさらにおすすめです。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4