IOã¢ã¯ã·ã§ã³ã²ã¨ã¤ã²ã¨ã¤ãå©ç¨è¨±è«¾ãã»ãã¹ãå¯è½ã«ãã
IOã®ãã¹ãã£ã¦ããã¸ãã ï¼ãããã©ãã«ãããããã«ï¼å 人ãã¡ã¯è²ã èãï¼
- å©ç¨å¯¾è±¡ã®ç¹å®IOã¢ã¯ã·ã§ã³ãæ éã«åæ¨é¸æãï¼MonadHogeIOã®ãããªåã¯ã©ã¹ã«ããã¤ã³ã¿ã¼ãã§ã¼ã¹ãä¸ãã¦ãããã®ã¤ã³ã¿ã¼ãã§ã¼ã¹ä¸ã®ã¢ã¯ã·ã§ã³ã¨ãã¦å®è£ ããï¼å®è¡æã¯ç®çã®ã¤ã³ã¹ã¿ã³ã¹ã®ä¸ã§èµ°ããããï¼ãã¹ãæã¯Mockç¨ã¤ã³ã¹ã¿ã³ã¹ã®ä¸ã§èµ°ããã
- åæ§ã«ç¹å®IOã¢ã¯ã·ã§ã³ãæ éã«åæ¨é¸æãï¼Freeã¢ãããOperationalã¢ããã«ããã¤ã³ã¿ã¼ãã§ã¼ã¹ãä¸ãã¦ä»¥ä¸ç¥ï¼ç®çã®ã©ã³ãã¼ã§èµ°ããããï¼ãã¹ãç¨ã®ã©ã³ãã¼ã§èµ°ãããããã
ã¨ãã£ãæ段ãåãï¼
ã§ï¼æ®éãã¹ãç¨ã®ãã®ã¯ãã¥ã¢ã«ãªãããã«å®è£ ãï¼ãã¹ãããããããï¼å ·ä½çã«ã¯ï¼型クラスとモナドと Free モナド - あどけない話ãï¼Freeモナドを超えた!?operationalモナドを使ってみよう - モナドとわたしとコモナドãããããããããªï¼
ã§ãï¼ã©ã¡ãã®æ¹æ³ãåãã«ããï¼IOã¢ã¯ã·ã§ã³ãé©åã«åæ¨é¸æãããç¶æ ã«ãªããã°ãªããªãï¼IOã¢ã¯ã·ã§ã³aã¨IOã¢ã¯ã·ã§ã³bã ã使ãIOã¢ã¯ã·ã§ã³x (x = a >> b)ã¨ï¼IOã¢ã¯ã·ã§ã³bã¨IOã¢ã¯ã·ã§ã³cã ã使ãIOã¢ã¯ã·ã§ã³y (y = b >> c)ãããã¨ãï¼a,b,cããããã«ç¸å½ããã¤ã³ã¿ã¼ãã§ã¼ã¹ãæã£ãåã¯ã©ã¹ãããã¼ã¿åã®ã³ã³ã¹ãã©ã¯ã¿ãããç¨æãããã¨ã«ãªãï¼ããã¯ï¼aã¨bã ãï¼bã¨cã ãã«ããããç¸å½ãããã¤ã ãæã£ããã®ãç¨æããã ãããï¼ãããã«ããï¼ç¹å®ã®ãã®ã«éå®ããç°å¢ãä½ã£ã¦ãã®ä¸ã§æ¦ããã¨ã«ãªãï¼ã¨ããã®ããã®ãããã®è©±
ãã¹ã¦ã® IO ãå¼ã¶é¢æ°ãå¾ãã注å
¥ããããã«ããã°ããã®ããªã
— matsumoto (@daimatz) 2014, 2æ 18
IOã®ãã¹ãã®ããã«Free使ããã¨ã¯ã©ã®ç¨åº¦åççããªã
— ruicc (@ruicc) 2014, 2æ 18
IOã®ãã¹ãã£ã¦èãã¦ããã¡ã¯ã©ã®æ¹æ³ã«ãåçæ§ã¯ç¡ãã®ã§ã¯ï¼ããããIOã¯æ¬å½ã¯ã©ããªã®ãå¶éã§ãã¦åãã¦è¼ãã¨ããã
— Noriyuki OHKAWA (@notogawa) 2014, 2æ 18
IOå¶éããããã«Free使ãã¾ããã
— ruicc (@ruicc) 2014, 2æ 18
IO ã®ç¨®é¡ãå¶éããã¨ããã®ããã¹ãã®æèã§ã©ãå¬ããã®ããã¾ãããã£ã¦ããªãã QuickCheck ã§ããã®ãå¬ããã®ã¯ããããã
— matsumoto (@daimatz) 2014, 2æ 18
MonadHogeIOåã¯ã©ã¹ãä½ã£ã¦Hogeã¨HogeMockãã¤ã³ã¹ã¿ã³ã¹ã«ãã¦æ¬çªã¯Hogeãã¹ãã¯HogeMockãæ¨è«ãããããã«ããã¨ã¢ã¯ã·ã§ã³ããããããï¼Freeã¢ããä½ãã¨ããã¢ã¯ã·ã§ã³ã®ç¨®é¡ã¯éå®ããï¼ã©ã£ã¡ã§ãçµå±IOã®ç¨®é¡ã¯å¶éããã¦ãªããã°ãªããªã
— Noriyuki OHKAWA (@notogawa) 2014, 2æ 18
æµãã¯å¤§ä½ããã£ã¦ããã¤ãããªã®ã ãã©æãåããå
æ°ãç¡ã
— matsumoto (@daimatz) 2014, 2æ 18
ã§ï¼ãã®è¨äºã®æ¬é¡ï¼ä¸ã®ãã¤ã¼ãã§ãå¶éããã¦ãªããã°ï¼ç¾©åæï¼ãã¿ããã«èªåã§ãè¨ã£ã¦ããã¦ï¼æããã¦ä»ã§ãæ¬å½ã«ãããªç¶æ ãªã®ãã¨ã¡ããã£ã¨èãã¦ã¿ãçµæãç°¡åã«ã©ã¤ãã©ãª(ã¾ã hackageã«ä¸ãã¦ãªã)ã«ãã¦ã¿ãï¼
ãã®ã©ã¤ãã©ãªã¯ï¼ã¶ãã¯ãªè¨ãã¨IOã¢ã¯ã·ã§ã³ã®å©ç¨å¶éåã³ã¢ãã¯å·®ãæ¿ããèªç±ã«è¡ãããã®ï¼ã¤ã³ã¿ã¼ãã§ã¼ã¹ã»åã¯ã©ã¹å¶ç´çæç³»åã³ï¼ãããå©ç¨ããä¾ã¨ãã¦ã®Preludeã®ç½®ãæãã¢ã¸ã¥ã¼ã«ã¨ãªã£ã¦ããï¼
TemplateHaskellã«ããä»»æã®IOã¢ã¯ã·ã§ã³ããextensible-effectsã®Effã¢ã¯ã·ã§ã³ãçæãï¼ããIOã¢ã¯ã·ã§ã³ã«å¯¾å¿ãã¦çæãããç¹å®ã®åã¯ã©ã¹å¶ç´ãã³ã³ããã¹ãã«ç¡ãå ´æã§ã¯ãã®IOã¢ã¯ã·ã§ã³ãå ã«çæãããEffã¢ã¯ã·ã§ã³ã¯ä½¿ããªãã¨ããå¶ç´ãä»ãããã¨ãã§ããï¼å ãã¦ï¼Effã¢ã¯ã·ã§ã³ãã³ã³ããã¹ãã«æã¤åã¯ã©ã¹å¶ç´ã«å¯¾ããã¤ã³ã¿ã¼ãã§ã¼ã¹ã ããã¢ãã¯å®è£ ããã°ãã®Effã¢ã¯ã·ã§ã³ã¯ãã¹ãå¯è½ã«ãªãï¼ã¨ãããã®ã ï¼
èªåã§ä¸æãè¨ãã¦ãªãã®ããã£ã¦ãã®ã§ãã¶ãä½è¨ã£ã¦ããããããªãã¨æãï¼ãã£ãã¨ãµã³ãã«ç¤ºããï¼
ã¾ãï¼IOã¢ã¯ã·ã§ã³ããEffã¢ã¯ã·ã§ã³ãçæããTemplateHaskellã«ã¤ãã¦ã ãï¼ãã¨ãã°ï¼Control.Genjitsu.THã®genjitsuã使ãï¼
import qualified Prelude as P $(genjitsu 'P.putStrLn)
ã®ããã«ããã¨ï¼ããã«ãã次ã®ãããªã³ã¼ããçæãããï¼
class AllowPutStrLn m where allowPutStrLn :: String -> m a instance AllowPutStrLn IO where allowPutStrLn = putStrLn putStrLn :: ( Typeable1 m , AllowPutStrLn m , Member (Lift m) r , SetMember Lift (Lift m) r) => String -> Eff r () putStrLn x = lift (allowPutStrLn x)
Prelude.Genjitsuã¢ã¸ã¥ã¼ã«ã¯ï¼ãããPreludeã®IOã¢ã¯ã·ã§ã³å ¨ã¦ã«è¡ãï¼å ã®ååã®é¢æ°ãæ°ãã«çæãããåãååã®é¢æ°ã§ç½®ãæãã¦ããã ãã ï¼
å®éã«Prelude.Genjitsuã使ãã¨æ¬¡ã®ãããªã³ã¼ãã«ãªãï¼
sample1 :: ( Typeable1 m , AllowReadLn m -- readLnã使ãã , AllowPutStrLn m -- putStrLnã使ãã , Member (Lift m) r , SetMember Lift (Lift m) r ) => Eff r () sample1 = do n <- readLn let s = n + 1 :: Int -- putStr "is denied" putStrLn (show s)
sample1ã¯åã®é¨åã«ç®ãæ½°ãã¨ï¼ä¸èº«ã¯ãã ã®IOã¢ããã®ããã«è¦ããï¼ãã ãï¼ãã®sample1ã®ã³ã³ããã¹ãã§ã¯ï¼readLnã¨putStrLnãã許ããã¦ããªãï¼ãã®ããï¼readLnã¨putStrLnã¯ä½¿ãããï¼putStrã使ããã¨ããã¨ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãªãï¼
ã¾ãï¼å¥ã®ã±ã¼ã¹ãè¦ã¦ã¿ããï¼
sample2 :: ( Typeable1 m , AllowPutStr m -- putStrã使ãã , AllowPutStrLn m -- putStrLnã使ãã , Member (Lift m) r , SetMember Lift (Lift m) r ) => Eff r () sample2 = do putStr "Start..." putStrLn "Done"
ãã¡ãã®sample2ã§ã¯ï¼putStrã使ããããã«ã³ã³ããã¹ãæå®ããã¦ããã®ã§putStrã使ããï¼
ãã¦ï¼ããããå®éã«IOã¢ã¯ã·ã§ã³ã«éå ãã¦ãããã®ã¯ç°¡åã ï¼extensible-effectsã®Liftã使ã£ã¦ããã®ã§runLiftãã¦ãããã°ããï¼
sample1IO :: IO () sample1IO = runLift sample1 sample2IO :: IO () sample2IO = runLift sample2
ã¾ãï¼sample1/sample2ã«å¯¾ãã¦ãã¹ããæ¸ãå ´åï¼ãããã®åã³ã³ããã¹ãã«ããåã¯ã©ã¹å¶ç´ã§è¨±å¯ããããã®ã ãã¤ã³ã¹ã¿ã³ã¹å®è£ ããã°ããï¼ãã¨ãã°ï¼sample1ããã¹ãããã®ã«Stateã¢ããã使ã£ã¦ã¿ãã¨ï¼
-- åèªé©åãªGHCæ¡å¼µã¯è£å®ãã¦ã newtype Mock1 a = Mock1 { runMock1 :: State String a } deriving ( Functor, Applicative , Monad, MonadState String, Typeable) -- sample1ã¯AllowReadLnãã³ã³ããã¹ãã«æã¤ã®ã§Mockå®è£ ãè¦æ±ããã¦ãã instance AllowReadLn Mock1 where allowReadLn = fmap read get -- sample1ã¯AllowPutStrLnãã³ã³ããã¹ãã«æã¤ã®ã§Mockå®è£ ãã instance AllowPutStrLn Mock1 where allowPutStrLn = put test1 = ((),"3") == runState (runMock1 $ runLift sample1) "2"
sample2ã®ã»ããåæ§ã«ãã¦pureãªãã¹ããæ¸ããã¨ãã§ããï¼sample2ã«ã¤ãã¦ã¯sample1ã¨ç°ãªããã¹ã対象ã¨ãã¦å ¥åã®ã¢ã¯ã·ã§ã³ãå«ã¾ãªãã®ã§Writerã¢ããã§ã¢ãã¯å®è£ ãã¦ãããã°ååã ããï¼ここまでのサンプルコード
genjitsuãMonadHogeIOã¤ã³ã¿ã¼ãã§ã¼ã¹ãFree/Operationalã¢ããæ¹å¼ã«å¯¾ãã¦æã¤å©ç¹ã¯ï¼
- å¿
è¦ãªã¯ã©ã¹ããã®çæãTemplateHaskellã§ã ãã¶ã©ã¯
- runLiftã§IOã¢ã¯ã·ã§ã³ã«æ»ãããã®ãå度genjitsuãã¦ãããããªãã¨ãç°¡å
- ãããããå©ç¨ãããã¢ã¯ã·ã§ã³ãåæ¨é¸æãã¦å¶éãã¦ããå¿
è¦ãç¡ã
- ãã®å ´ãã®å ´ã§æ¬å½ã«å¿ è¦ãªãã³ã³ããã¹ãã¨ãã¦ä¸ããã°ãã
- ã¢ã¯ã·ã§ã³åä½ã®å©ç¨è¨±å¯ãåã§è¡¨ããã¨ãã§ãã
- ã¦ã«ãã«ããããªç¨®é¡ã®IOã¢ã¯ã·ã§ã³ã使ã£ã¦ãã¾ããããªãã¨ãé²ãã
- ä½ãå®è£
ããã°èµ°ããããã¨ãã§ããããåã¬ãã«ã§æ確ã«ãªã
- 許å¯ããã¦ãããã®ã«å¯¾ãã¦ã®ã¿å®è£ ãä¸ããã°èµ°ã
- ã¢ãã¯æ¸ãããããã¨ãã«çç®ãã¦ãããã¹ã対象ã«å¯¾ãã¦ä½è¨ãªã¤ã³ã¿ã¼ãã§ã¼ã¹ãæ°ã«ããªãã¦ãã
ã¨ãï¼ãã®ã¸ãï¼
æè¦çã«ã ãã¶æ¥½ã ã¨æããã ãã©ã©ãã ãããï¼æ£ç´ãªã¨ããè¨ãã¨ã³ã³ã»ããã«ã¤ãã¤ãèªä¿¡ãç¡ãã®ã§hackageã«ã¯ä¸ãã¦ãªãï¼