Skip to content

Instantly share code, notes, and snippets.

@PhilOwen
Last active January 1, 2018 06:54
Show Gist options
  • Save PhilOwen/b9f27c61f5458f0df478fbf478d37604 to your computer and use it in GitHub Desktop.
Save PhilOwen/b9f27c61f5458f0df478fbf478d37604 to your computer and use it in GitHub Desktop.
ReaderTでIOの状態を取り回す

HaskellのReaderTを使って、IOをうまく回そうとしてみる。

Haskellで低レベルなハードウェアの処理をやっていたら、 ファイルオブジェクトを持ち回るのが嫌だなぁと思った。 そこで、Readerモナドから状態を取って来ればいいんじゃね、 というわけでReaderを使う。 ただ、IO処理なので普通のReaderではダメで、 ReaderTでやらないといけないらしい。

openSthreadSthという関数が与えられたとして、 それをReaderTで扱ってみた。 (与えられた関数は、実装がテキトー)

さらにMaybeを使って、失敗時に中断させた。
main内は、IOモナドの中にまずReaderモナドが来て、 その中にMaybeモナドが来ている。 型がかなり複雑な事になっている…。 また、モナドを積み上げる順番に注意。

Reference

import Control.Monad.Trans
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Reader
import Control.Monad.IO.Class
import System.Random
type DescReaderIO = ReaderT Int IO
main = do
fd <- openSth "foo.txt"
css <- flip runReaderT fd $ do
runMaybeT $ do
x <- maybeReadSth
y <- maybeReadSth
z <- maybeReadSth
return (x, y, z)
print css
maybeReadSth :: MaybeT DescReaderIO String
maybeReadSth = MaybeT $ (fmap f) readerReadSth where
f "" = Nothing
f cs = Just cs
readerReadSth :: DescReaderIO String
readerReadSth = do
fd <- ask
liftIO $ readSth fd
-- External
openSth :: FilePath -> IO Int
openSth filepath = do
let fd = length filepath
putStrLn $ unwords [filepath, "opened: id", show fd]
return fd
readSth :: Int -> IO String
readSth fd = do
r <- randomRIO (0, 20) :: IO Int
return $ show r
name: readert-test
version: 0.1.0.0
build-type: Simple
cabal-version: >=1.10
executable readert-test
main-is: Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base
, mtl
default-language: Haskell2010
resolver: lts-10.1
packages:
- '.'
extra-deps: []
flags: {}
extra-package-dbs: []
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment