線形型でリソース管理をする例
これから関心あるとこだけ抜き出して、ちょっと書き換えてみたmrsekut.icon code:hs
{-# LANGUAGE QualifiedDo #-} module Hoge where
import qualified Control.Functor.Linear as Control
import Data.Text
import Data.Unrestricted.Linear
import qualified System.IO as System
import qualified System.IO.Resource as Linear
linearGetFirstLine :: FilePath -> Linear.RIO (Ur Text)
linearGetFirstLine fp = Control.do
handle <- Linear.openFile fp System.ReadMode
(t, handle') <- Linear.hGetLine handle
Linear.hClose handle' -- 例えばココをコメントアウトすると型エラー
Control.return t
-- 使用している関数の型
-- Lienear.openFile :: FilePath -> IOMode -> RIO Handle
-- Linear.hGetLine :: Handle %1 -> RIO (Ur Text, Handle)
-- Linear.hClose :: Handle %1 -> RIO ()
-- Control.return :: Monad m => a %1 -> m a
-- Control.(>>=) :: m a %1 -> (a %1 -> m b) %1 -> m b
Linear.hGetLine :: Handle %1 -> RIO (Ur Text, Handle)は、
handleを1つだけ消費し、新しいhandle'を返す
Linear.hClose :: Handle %1 -> RIO ()は、
hCloseは、handle'を1つだけ消費し、新しいhandleは返さない
線形型用のMonadのbindは、(>>=) :: m a %1 -> (a %1 -> m b) %1 -> m b
即ち、
元のコードの<-の左辺の値は、そのdo式の中で1回だけ使われる
ということを表す
具体的に言えば
上のコードの、handleやhandle'やtは、do式内で1回だけ使用される必要がある
ちなみに、上のコードを脱糖したもののイメージはこんな感じになる
code:hs
linearGetFirstLine' fp =
openFile fp System.ReadMode >>= \handle ->
hGetLine handle >>= \(t, handle') ->
hClose handle' >>= \_ ->
return t
だから
hCloseを書き忘れるとerror
なぜならhandle'が使用されていないから
openFile ..を2回書くとerror
なぜならhandleが2回使用されるから
hCloseを2回書くとerror
なぜなら、handle'が2回使用されるから
参考