é·ãéãFPãšHaskellã«ã€ããŠHabrã«æçšãªãã®ãäœãæžããŠããããæè¡èšäºã®å®å
šã«åªããçç±ãããããšã«æ°ã¥ããã®ã§ãç§ã¯æãæ¯ãããšã«æ±ºããŸããã ãã®èšäºã§ã¯ãADTïŒä»£æ°ããŒã¿åïŒãšMVarïŒç«¶åå¯å€å€æ°ïŒã䜿çšããŠãããªãŒã¢ããã«å®è£
ãã
Software Trasactional MemoryïŒSTMïŒã«çŠç¹ãåœãŠãŸãã ãããŠãäžè¬ã«ãæŠå¿µå®èšŒã¯ãå®éã®ãSTMãšæ¯èŒããŠéåžžã«ã·ã³ãã«ã§ããããšã倿ããŸããã ããã«ã€ããŠè°è«ããŸãããã
ãœãããŠã§ã¢ãã©ã³ã¶ã¯ã·ã§ã³ã¡ã¢ãª
STMã¯ãç«¶äºåã®ããããŒã¿ã¢ãã«ãããã°ã©ãã³ã°ããããã®ã¢ãããŒãã§ãã ããã§ã®ç«¶äºã¯ãã¢ãã«ã®ããŸããŸãªéšåãäºãã«ç¬ç«ããŠç°ãªãã¹ã¬ããã§æŽæ°ãããå
±æãªãœãŒã¹ã®ç«¶åããã©ã³ã¶ã¯ã·ã§ã³ã䜿çšããŠè§£æ±ºãããããšã§ãã ãã©ã³ã¶ã¯ã·ã§ã³ã¯ããŒã¿ããŒã¹ã®ãã©ã³ã¶ã¯ã·ã§ã³ãšäŒŒãŠããŸãããããã€ãã®éãããããŸãã ã³ãŒãå
ã®ããŒã¿ã®äžéšã倿ŽãããšããŸãã æŠå¿µçã«ã¯ãã³ãŒããã¢ãã«ã«çŽæ¥æžã蟌ãŸããã®ã§ã¯ãªããå¿
èŠãªéšåã®ã³ããŒã§æ©èœãããšæ³å®ã§ããŸãã æåŸã«ãSTMãšã³ãžã³ã¯ãã©ã³ã¶ã¯ã·ã§ã³ãéããæåã«é¢å¿ã®ããã¢ãã«ã®éšåã誰ã«ãã£ãŠã倿ŽãããŠããªãããšã確èªããŸãã 倿ŽããŸããã§ãããïŒ ããŠãæ°ããå€ã¯ä¿®æ£ãããŸãã ããªãã®åã«èª°ãã管çããŸãããïŒ ããã¯ç«¶åã§ããæ°ããããŒã¿ã§èšç®ãåéããŠãã ããã æŠç¥çã«ã¯ãããã¯æ¬¡ã®ããã«è¡šãããšãã§ããŸãã

ããã§ãã¢ãããã¯æäœã¯ã¹ã¬ããã«ãã£ãŠäžŠåã«å®è¡ãããŸãããã¢ãã«ã®å¯å€éšåãžã®ã¢ã¯ã»ã¹ããããã¯ãããã©ã³ã¶ã¯ã·ã§ã³å
ã§ã®ã¿ã³ããããããŸãã
STMã«ã¯ããŸããŸãªããªãšãŒã·ã§ã³ããããŸãããæåãªäœå
ãComposable Memory Transactionsãã§ææ¡ããããã®ã«ã€ããŠå
·äœçã«ã話ããŸãã
- ããŒã¿ã¢ãã«ã®æŠå¿µãšãã®äžã®èšç®ã¯åé¢ãããŠããŸãã
- ã³ã³ãã¥ãŒãã£ã³ã°ã¯STMã¢ããã§ãããFPãã©ãã€ã ã«å®å
šã«æºæ ããŠæ§æã§ããŸãã
- æåã§èšç®ãåéãããšããæŠå¿µããããŸãïŒå詊è¡ïŒã
- æåŸã«ãHaskellã®åªããå®è£
ããããŸãããããã¯èæ
®ããŸããããèªåã®ã€ã³ã¿ãŒãã§ã€ã¹ã®ãããªãã®ã«çŠç¹ãåãããŸãã
ã¢ãã«ã«ã¯ãä»»æã®ããŒã¿æ§é ã䜿çšã§ããŸãã STMã©ã€ãã©ãªã¯ã倿°ïŒ
TVar ïŒããã¥ãŒïŒ
TQueue ïŒãé
åïŒ
TArray ïŒãªã©ãããŸããŸãªããªããã£ããæäŸããŸãã ãã©ã³ã¶ã¯ã·ã§ã³å€æ°-TVar'iïŒ "ã¯ãªãã¿ãŒ"ïŒ-ã¯ãæ¬æ ŒçãªSTMã«ã¯ãã§ã«æå°éã§ãããä»ã®ãã¹ãŠã¯ããããéããŠè¡šçŸãããŠãããšæšæž¬ã§ããŸãã
ããšãã°ã
é£äºããå²åŠè
ã®
åé¡ãèããŠã¿ãŸãããã ãã©ãŒã¯ã¯ãç«¶äºåã®ããã¢ã¯ã»ã¹ãæ§ç¯ããããã«å¿
èŠãªå
±éãªãœãŒã¹ãšããŠæ³åã§ããŸãã
data ForkState = Free | Taken type TFork = TVar ForkState data Forks = Forks { fork1 :: TFork , fork2 :: TFork , fork3 :: TFork , fork4 :: TFork , fork5 :: TFork }
ãã®ã¢ãã«ã¯æãåçŽã§ããåãã©ãŒã¯ã¯ç¬èªã®ãã©ã³ã¶ã¯ã·ã§ã³å€æ°ã«æ ŒçŽããããã¢ã§äœæ¥ããå¿
èŠããããŸãïŒ
ïŒfork1ãfork2ïŒãïŒfork2ãfork3ïŒã...ïŒfork5ãfork1ïŒ ã ãããããã®ãããªæ§é ã¯ãã£ãšããŸãæ©èœããŸããã
type Forks = TVar [ForkState]
å
±æãªãœãŒã¹ã¯1ã€ãããªããå²åŠçãªã¹ããªãŒã ã5ã€ããå Žåããããã¯é çªã«ã³ãããããæš©å©ãåãåããŸãã ãã®çµæã1人ã®å²åŠè
ã ããé£äºãããä»ã®4人ãèããæ¬¡ã«å¥ã®äººãé£äºãããŸãããçè«çã«ã¯5ã€ã®ãã©ãŒã¯ã§2人ãåæã«é£äºãããããšãã§ããŸãã ãããã£ãŠãæãæåŸ
ãããåäœãæäŸããç«¶åã¢ãã«ãäœæããå¿
èŠããããŸãã STMã¢ããã®èšç®ã¯ãåå¥ã®ã¯ãªãŒãã£ãŒãã©ãŒã¯ãæã€ã¢ãã«ã«å¯ŸããŠã©ã®ããã«èŠãããã瀺ããŸãã
data ForkState = Free | Taken type TFork = TVar ForkState takeFork :: TFork -> STM Bool takeFork tFork = do forkState <- readTVar tFork when (forkState == Free) (writeTVar tFork Taken) pure (forkState == Free)
ãã©ã°ãè§£æŸãããæ£åžžã«ãååŸããããå Žåãã€ãŸã
tForkãäžæžããããå Žåã颿°ã¯
Trueãè¿ããŸãã ãã©ã°ããã§ã«åäœããŠããå Žåã¯ãFalseã«ãªããè§ŠããããŸããã æ¬¡ã«ãããã€ãã®ãã©ãŒã¯ã«ã€ããŠèããŸãã 5ã€ã®ç¶æ³ããããŸãã
- äž¡æ¹ãšãç¡æã§ã
- å¿ãããŸãŸïŒå·Šé£ïŒãå³ã¯ç¡æ
- å·Šãç¡æãå³ãå¿ããïŒå³é£ïŒ
- äž¡æ¹ãšãå¿ããïŒé£äººïŒ
- ã©ã¡ããå¿ããïŒå²åŠè
ã«ããïŒ
ç§ãã¡ã¯ä»ãç§ãã¡ã®å²åŠè
ã«ããäž¡æ¹ã®åå²ã®åãæ¹ãæžããŸãïŒ
takeForks :: (TFork, TFork) -> STM Bool takeForks (tLeftFork, tRightFork) = do leftTaken <- takeFork tLeftFork rightTaken <- takeFork tRightFork pure (leftTaken && rightTaken)
ãã®ã³ãŒãã§ã¯ã1ã€ã®ãã©ã°ïŒããšãã°ãå·Šã®ãã©ã°ïŒã䜿çšã§ããŸãããå¥ã®ãã©ã°ïŒããšãã°ãé£äººãå æããŠããããšã倿ããå³ã®ãã©ã°ïŒã¯äœ¿çšã§ããªãããšã«æ°ä»ããããããŸããã ãã¡ãããã®å Žåã
takeForks颿°ã¯
Falseãè¿ããŸããã1ã€ã®ãã©ãŒã¯ããŸã å²åŠè
ã®æäžã«ãããšããäºå®ã¯ã©ãã§ããããïŒ åœŒã¯äžäººã§é£ã¹ãããšãã§ããªãã®ã§ãå
ã«æ»ããªããã°ãªããããããã°ããèãç¶ããªããã°ãªããŸããã ãã®åŸãäž¡æ¹ã®ãã©ãŒã¯ãç¡æã«ãªãããšãæåŸ
ããŠãããäžåºŠè©Šãããšãã§ããŸãã
ããããSTMã®èгç¹ããã®ããããããã¯ãã¯ãä»ã®ç«¶åæ§é ã®èгç¹ããããç°ãªãæ¹æ³ã§å®è£
ãããŸãã
tLeftForkãš
tRightForkã®äž¡æ¹ã®å€æ°ã¯ãä»ã®å²åŠè
ã«ãã£ãŠåããªãœãŒã¹ã«æ¥ç¶ãããŠããªãããŒã«ã«ã³ããŒã§ãããšæ³å®ã§ããŸãã ãããã£ãŠããã©ã°ãã眮ããããšã¯ã§ããŸãããã倱æããããšãèšç®ã«äŒããããšãã§ããŸãã ãã®å Žåã1ã€ã®ãã©ãŒã¯ã¯å
±æãªãœãŒã¹ã«æžã蟌ãŸããŸãã-ãšã«ããã
takeForkã®åŒã³åºããæåããŸãã
ã§ãã ã ããã¯éåžžã«äŸ¿å©ã§ãããHaskelian STMå®è£
ãä»ã®ãã®ããåºå¥ããã®ã¯ãçŸåšã®ã¢ããèšç®ã®ããã£ã³ã»ã«ãæäœã§ãã
ãã£ã³ã»ã«ããããã®ç¹å¥ãª
åè©Šè¡æ¹æ³ããããŸããããã䜿çšããŠ
takeForksãæžãæããŸãããã
takeForks :: (TFork, TFork) -> STM () takeForks (tLeftFork, tRightFork) = do leftTaken <- takeFork tLeftFork rightTaken <- takeFork tRightFork when (not leftTaken || not rightTaken) retry
äž¡æ¹ã®åå²ç¹ãå²åŠè
ã«ãã£ãŠäžåºŠã«ååŸãããå Žåãèšç®ã¯æåããŸãã ãã以å€ã®å Žåã¯ãäžå®ã®ééã§äœåºŠãåèµ·åããŸãã ãã®ããŒãžã§ã³ã§ã¯ãäž¡æ¹ã®ãªãœãŒã¹ãæ£åžžã«ãã£ããã£ããããã©ãããç¥ãå¿
èŠããªãããã
Boolãè¿ããŸããã 颿°ãå®è¡ãããèšç®ããã¡ã€ã«ããªãå Žåãæ£åžžã«å®è¡ãããããšãæå³ããŸãã
åå²ç¹ããšã£ãåŸãããšãã°å²åŠè
ããé£ã¹ããç¶æ
ã«ãããªã©ãäœãä»ã®ããšãããå¿
èŠãããã§ãããã
takeForksãåŒã³åºããåŸã«ãããè¡ãã ãã§ãSTMã¢ããã¯ãã¯ãªãŒãã£ãŒãã®æ¡ä»¶ãäžè²«ããŠããããšã確èªããŸãã
data PhilosopherState = Thinking | Eating data Philosopher = Philosopher { pState :: TVar PhilosopherState , pLeftFork :: TFork , pRrightFork :: TFork } changePhilosopherActivity :: Philosopher -> STM () changePhilosopherActivity (Philosopher tState tLeftFork tRightFork) = do state <- readTVar tState case state of Thinking -> do taken <- takeForks tFs unless taken retry
ãã®ã¡ãœããã®å®å
šãªå®è£
ã¯æŒç¿ãšããŠæ®ããæåŸã®ããã·ã³ã°ãªã³ã¯ã«ã€ããŠæ€èšããŸãã ãšããããããã©ã³ã¶ã¯ã·ã§ã³ã¢ãã«ã®ããžãã¯ã®ã¿ã説æããŸããããç¹å®ã®
TVarããŸã äœæããŠããããäœãéå§ããŠããŸããã ããããã£ãŠã¿ãŸãããïŒ
philosoperWorker :: Philosopher -> IO () philosoperWorker philosopher = do atomically (changePhilosopherActivity philosopher) threadDelay 5000 philosoperWorker philosopher runPhilosophers :: IO () runPhilosophers = do tState1 <- newTVarIO Thinking tState2 <- newTVarIO Thinking tFork1 <- newTVarIO Free tFork2 <- newTVarIO Free forkIO (philosoperWorker (Philosopher tState1 tFork1 tFork2)) forkIO (philosoperWorker (Philosopher tState2 tFork2 tFork1)) threadDelay 100000
ã¢ãããã¯ã«ïŒSTM a-> IO aã³ã³ãããŒã¿ãŒã¯ã
STMã¢ããã§ã¢ãããã¯ã«èšç®ãå®è¡ããŸãã ã¿ã€ããããç«¶åã¢ãã«ã§åäœããçŽç²ãªéšåã¯ã
IOã¢ããã®ã¯ãªãŒã³ã§ãªãã³ã³ãã¥ãŒãã£ã³ã°ããåé¢ãããŠããããšãããããŸãã STMã³ãŒãã¯å¹æããããŸããã ããè¯ã-ãŸã£ãããããŸãããããããªããšãåèµ·åæã«ããã€ãã®å¥åŠãªçµæãåŸãããŸããããšãã°ããã¡ã€ã«ã«æžã蟌ãã å Žåãå Žåã«ãã£ãŠã¯åœã®ãšã³ããªãååŸã§ããŸããããã®ãšã©ãŒããã£ããããã®ã¯éåžžã«å°é£ã§ãã ãããã£ãŠã
STMã¢ããã«ã¯çŽç²ãªèšç®ãããªãããã®å®è¡ã¯ã¢ãããã¯æäœã§ãããšæ³å®ã§ããŸãããä»ã®èšç®ã¯ãããã¯ããŸããã
TVar newTVarIO :: a-> IOïŒTVar aïŒãäœæãã颿°
ãæ±ããŠããŸãããçŽç²ãªã³ã³ãããŒã¿
newTVar :: a-> STMïŒTVar aïŒã䜿çšããŠ
STMå
ã§æ°ãã
TVarãäœæããããšã劚ãã
ãã®ã¯ãããŸããã å¿
èŠãªãã£ãã ãã§ãã æ°é
ãã®ãã人ã¯ããã©ãŒã¯ã ããå
±æãªãœãŒã¹ã§ãããå²åŠè
èªèº«ã®ç¶æ
ã䟿å®äž
TVarã§ã©ãããããŠããããšã«
æ°ä»ãã§ããã ã
ãŸãšãããšã
STMã®æå°å®è£
ã«ã¯ã
TVarã
æäœããããã®æ¬¡ã®æ©èœãå«ãŸããŠããå¿
èŠããããŸãã
newTVar :: a -> STM (TVar a) readTVar :: TVar a -> STM a writeTVar :: TVar a -> a -> STM ()
èšç®ã®å®è¡ïŒ
atomically :: STM a -> IO a
æåŸã«ãèšç®ãåéããæ©èœã¯éåžžã«ãã©ã¹ã«ãªããŸãã
retry :: STM a
ãã¡ãããã©ã€ãã©ãªã«ã¯ãããšãã°
STMã® Alternativeåã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãªã©ãä»ã«ãéåžžã«å€ãã®äŸ¿å©ãªæ§æèŠçŽ ããããŸãããç¬ç«ããåŠç¿ã®ããã«æ®ããŸãããã
ããªãŒã¢ããã®STM
é©åã«åäœããSTMãå®è£
ããããšã¯é£ãããšèããããŠãããã³ã³ãã€ã©ãŒããã®ãµããŒããããã°è¯ãã§ãã HaskellãšClojureã®å®è£
ã¯çŸæç¹ã§æé«ã§ãããä»ã®èšèªã§ã¯STMã¯çŸå®çã§ã¯ãªããšèããŠããŸãã åœä»€åèšèªã§èšç®ãåéãã广ãå¶åŸ¡ããããšãã§ããã¢ããSTMã¯ååšããªããšæ³å®ã§ããŸãã ããããããã¯ãã¹ãŠæ idleãªæšè«ã§ãããç§ã¯ééã£ãŠãããããããŸããã æ®å¿µãªãããä»ã®ãšã³ã·ã¹ãã ã¯èšããŸã§ããªãã
stm haskelã©ã€ãã©ãªãŒã®å
éšããçè§£ã§ããŸããã ããã§ããã€ã³ã¿ãŒãã§ã€ã¹ã®èгç¹ããèŠããšããã«ãã¹ã¬ããç°å¢ã§ã³ãŒããã©ã®ããã«åäœãããã¯æããã§ãã ãããŠãã€ã³ã¿ãŒãã§ãŒã¹ïŒãµããžã§ã¯ãæåèšèªïŒãšäºæ³ãããåäœã®ä»æ§ãããå Žåãããã¯ãã§ã«ãããªãŒã¢ããã䜿çšããŠç¬èªã®STMãäœæããããšããã®ã«ååã§ãã
ã ããã
ç¡æã®ã¢ãã ã Freeã¢ããäžã«æ§ç¯ãããDSLã«ã¯ã次ã®ç¹æ§ããããŸãã
- äžå
çã«æ§æå¯èœãªçŽç²ãªDSLãã€ãŸãæ¬åœã«æ©èœããŸãã
- ãã®ãããªDSLã®ã³ãŒãã«ã¯ããµããžã§ã¯ãé åã«å ããŠäœåãªãã®ã¯å«ãŸããŸãããã€ãŸããèªã¿ããããçè§£ãããããšããããšã§ãã
- ã€ã³ã¿ãŒãã§ã€ã¹ãšå®è£
ã¯å¹æçã«åé¢ãããŠããŸãã
- ããã€ãã®å®è£
ããããå®è¡æã«çœ®ãæããããšãã§ããŸãã
ç¡æã®ã¢ããã¯éåžžã«åŒ·åãªããŒã«ã§ããã
Inversion of Controlãå®è£
ããããã®ãæ£ãããçŽç²ã«æ©èœçãªã¢ãããŒããšèããããšãã§ããŸãã ç§ã®èãã§ã¯ããµããžã§ã¯ãé åã®åé¡ã¯ãFree-monadic DSLã®å©ããåããŠè§£æ±ºããããšãã§ããŸãã ãã®ãããã¯ã¯éåžžã«åºç¯å²ã§ããã颿°åããã°ã©ãã³ã°ã®ãœãããŠã§ã¢èšèšãšã¢ãŒããã¯ãã£ã®å€ãã®åé¡ã«é¢ä¿ããŠãããããä»ã®è©³çްã¯å³ããçããŸãã 奜å¥å¿peopleçãªäººã¯ãã€ã³ã¿ãŒãããäžã®å€æ°ã®æ
å ±æºããŸãã¯ç¡æã®ã¢ãããç¹å¥ãªæ³šæãæãããŠããç§ã®å
æ¬ã®Functional Design and Architectureã«ç®ãåããããšãã§ããŸãã
ã§ã¯ã
stm-freeã©ã€ãã©ãªã®ã³ãŒããèŠãŠã¿ãŸãããã
STMã¯ãã©ã³ã¶ã¯ã·ã§ã³ã¢ãã«ãäœæããããã®ãµããžã§ã¯ãæåèšèªã§ãããããã¯ãªãŒã³ã§å調ã§ããæå°éã®STMã®å Žåãç¡æDSLã«ã¯TVarãæäœããããã®åãã¡ãœãããå«ãŸããŠããå¿
èŠããããŸããç¡æã®ã¢ããã ãŸããTVarãšã¯äœãã倿ããŸãã
type UStamp = Unique newtype TVarId = TVarId UStamp data TVar a = TVar TVarId
ãã¯ãªãŒãã£ãŒããåºå¥ããå¿
èŠããããããåã€ã³ã¹ã¿ã³ã¹ã¯äžæã®å€ã§èå¥ãããŸãã ã©ã€ãã©ãªãŠãŒã¶ãŒã¯ãããç¥ãå¿
èŠã¯ãããŸãã
ãTVaraåã䜿çšããããšãæåŸ
ãããŸãã ãã®ã¿ã€ãã®å€ãæ±ãããšã¯ãå°ããªSTMã®åäœã®ååã§ãã ãããã£ãŠãé©åãªæ¹æ³ã§
ADTãå®çŸ©ããŸãã
data STMF next where NewTVar :: a -> (TVar a -> next) -> STMF next WriteTVar :: TVar a -> a -> next -> STMF next ReadTVar :: TVar a -> (a -> next) -> STMF next
ãããŠãããã§ããè©³çŽ°ã«æ»åšããå¿
èŠããããŸãã
ãªããããè¡ãå¿
èŠãããã®ã§ããïŒ èŠããã«ãFree Monadã¯äœããã®eDSLã®äžã«æ§ç¯ããå¿
èŠããããšããããšã§ãã æãç°¡åãªèšå®æ¹æ³ã¯ãå¯èœãªã¡ãœãããADTã³ã³ã¹ãã©ã¯ã¿ãŒã®åœ¢åŒã§å®çŸ©ããããšã§ãã ãšã³ããŠãŒã¶ãŒã¯ãã®ã¿ã€ãã§ã¯åäœããŸããããããã䜿çšããŠãäœããã®å¹æã®ããã¡ãœãããè§£éããŸãã æããã«ãNewTVarã¡ãœããã¯ããæ°ããTVarãäœæãããçµæãšããŠè¿ãããããšããçµæã§è§£éãããå¿
èŠããããŸãã ããããããšãã°ããŒã¿ããŒã¹ããã°ãžã®æžã蟌ã¿ããŸãã¯å®éã®STMãžã®åŒã³åºããªã©ãäœãä»ã®ããšãè¡ãã€ã³ã¿ãŒããªã¿ãŒãäœæã§ããŸãã
ãããã®ã³ã³ã¹ãã©ã¯ã¿ã«ã¯ãè§£éããå¿
èŠããããã¹ãŠã®æ
å ±ãå«ãŸããŠããŸãã
NewTVarã³ã³ã¹ãã©ã¯ã¿ãŒã«ã¯ããŠãŒã¶ãŒå®çŸ©ã®å€
aãå«ãŸããŠãããè§£éæã«ãã®å€ãæ°ããTVarã«å
¥ããŸãã ãããåé¡ã¯ã
NewTVarãžã®åŒã³åºãããšã«
aãç¬èªã®ãã®ã§ãªããã°ãªããªãããš
ã§ã ã
次ã®aã«
STMFãèšè¿°ããå Žåãããã€ãã®
NewTVaråŒã³åºãã
çµã³ä»ããããŠãããã¹ãŠã®ã³ãŒãã«æ¢ã«å
±éããŠããŸãïŒ
data STMF next a where NewTVar :: a -> (TVar a -> next) -> STMF next
ããããããã¯ç¡æå³ã§ãããªããªããç§ãã¡ã¯ãŸã ä»»æã®åã«
NewTVarã䜿çšãããããã§ãã ãããã£ãŠãç¹å®ã®ã¡ãœããã®ã¿ã®ããŒã«ã«å¯èŠæ§ã§
aãåé€
ããŸãã
ãæ³šæ å®éãProof of Conceptã®äœæ¥ãé«éåããããã«ãã·ãªã¢ã«åã§ããããã«aãå
¥åããããã«å¶éãããŠããŸãïŒ aesonã©ã€ãã©ãªã®ToJSON / FromJSONã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ïŒã å®éããããã®ããŸããŸãªã¿ã€ãã®TVarããããã«ä¿åããå¿
èŠããããŸããã Typeable / Dynamic ãç¹ã«HListsãå°ç¡ãã«ããããããŸããã å®éã®STMã§ã¯ãã¿ã€ãaã¯é¢æ°ã§ãã絶察ã«äœã§ãããŸããŸããã ãŸãããã®åé¡ã«ã€ããŠã¯åŸã»ã©å¯ŸåŠããŸãã
ãã®
次ã®ãã£ãŒã«ãã¯ã©ã®ãããªãã®ã§ããïŒ ããã§ã¯ãFree Monadããã®èŠæ±ã«å¿ããŸãã 圌女ã¯çŸåšã®ã¡ãœããã®ç¶ç¶ãã©ããã«ä¿åããå¿
èŠãããã
次ã®ãã£ãŒã«ãã¯åœŒå¥³ã«é©ããŠããªã-ADTã¯ãã®ãã£ãŒã«ãã®ãã¡ã³ã¯ã¿ãŒã§ããã¹ãã ã ãããã£ãŠã
NewTVarã¡ãœããã¯
TVar aãè¿ãå¿
èŠããããç¶ç¶
ïŒTVar a-> nextïŒã¯æ°ããå
¥å倿°ãåŸ
ã£ãŠããã ãã§ããããšã
ããããŸãã äžæ¹ã
WriteTVarã¯æçšãªãã®ãäœãè¿ããªããããç¶ç¶ã¯
nextåã§ããã€ãŸããäœãå
¥åããããšã¯ãããŸããã
STMFã¿ã€ãã®
ãã¡ã³ã¯ã¿ãŒã®äœæ
ã¯ç°¡åã§ãã
instance Functor STMF where fmap g (NewTVar a nextF) = NewTVar a (g . nextF) fmap g (WriteTVar tvar a next ) = WriteTVar tvar a (g next) fmap g (ReadTVar tvar nextF) = ReadTVar tvar (g . nextF)
ããè峿·±ã質åã¯ãSTMã®ã«ã¹ã¿ã ã¢ãããæçµçã«ã©ãã«ãããã§ãã ããã«ãããŸãïŒ
type STML next = Free STMF next
STMFåã
Freeåã§ã©ãããã
ããã«å¿
èŠãªãã¹ãŠã®ã¢ããããããã£ã
远å ããŸããã ããåºãã®
STMFã¡ãœããã®äžã«äžé£ã®äŸ¿å©ãªã¢ãã颿°ãäœæããã ãã§ãã
newTVar :: ToJSON a => a -> STML (TVar a) newTVar a = liftF (NewTVar a id) writeTVar :: ToJSON a => TVar a -> a -> STML () writeTVar tvar a = liftF (WriteTVar tvar a ()) readTVar :: FromJSON a => TVar a -> STML a readTVar tvar = liftF (ReadTVar tvar id)
ãã®çµæãTVarã®åœ¢åŒã®ãã©ã³ã¶ã¯ã·ã§ã³ã¢ãã«ã§æ¢ã«åäœããããšãã§ããŸãã å®éãé£äºã®å²åŠè
ã®äŸãåãäžããŠã
STMã
STMLã«ç°¡åã«çœ®ãæããããšãã§ããŸãã
data ForkState = Free | Taken type TFork = TVar ForkState takeFork :: TFork -> STML Bool takeFork tFork = do forkState <- readTVar tFork when (forkState == Free) (writeTVar tFork Taken) pure (forkState == Free)
ç°¡ååå©ïŒ ããããç§ãã¡ãèŠéããããšããããŸãã ããšãã°ã
å詊è¡ã®èšç®ã
äžæããæ¹æ³ã 远å ããã®ã¯ç°¡åã§ãïŒ
data STMF next where Retry :: STMF next instance Functor STMF where fmap g Retry = Retry retry :: STML () retry = liftF Retry
ç§ã®ã©ã€ãã©ãªã«ã¯å§ãšããããªéãããããŸãã ç¹ã«ãããã®
å詊è¡ã¡ãœããã¯
Unitãè¿ããŸãããä»»æã®å
aãè¿ãå¿
èŠããããŸãã ããã¯åºæ¬çãªå¶éã§ã¯ãªããPoCã®æ¥éãªçºå±ã®ææç©ã§ãããä»åŸä¿®æ£ããŸãã ããã«ããããããããã®ã³ãŒãã§ãããã¢ããèªäœã眮ãæããããšãé€ããŠã倿Žãªãã§æ®ããŸãã
takeForks :: (TFork, TFork) -> STML () takeForks (tLeftFork, tRightFork) = do leftTaken <- takeFork tLeftFork rightTaken <- takeFork tRightFork when (not leftTaken || not rightTaken) retry
Monadic eDSLã¯åºæ¬å®è£
ã«å¯èœãªéã䌌ãŠããŸãããSTMLã¹ã¯ãªããã®èµ·åã¯ç°ãªããŸãã ç§ã®
ã¢ãããã¯ãªã³ã³ã
ããŒã¿ãŒã¯ãåºæ¬å®è£
ãšã¯ç°ãªãã远å ã®åŒæ°ïŒèšç®ãã¹ãã³ããã³ã³ããã¹ãïŒãåããŸãã
atomically :: Context -> STML a -> IO a
ã³ã³ããã¹ãã¯ãŠãŒã¶ãŒããŒã¿ãTVarã®åœ¢åŒã§ä¿åãããããããã€ãã®ç°ãªãã³ã³ããã¹ãã䜿çšã§ããŸãã ããã¯ãããšãã°ããã©ã³ã¶ã¯ã·ã§ã³ã¢ãã«ãåé¢ããå Žåã«åœ¹ç«ã¡ãŸããããã«ãããçžäºã«åœ±é¿ãäžããŸããã ããšãã°ãããã¢ãã«ã§ã¯èšå€§ãªéã®ãŠãŒã¶ãŒããŒã¿ãäœæãããå¥ã®ã¢ãã«ã§ã¯TVarã»ããã¯ãŸã£ãã倿ŽãããŸããã æ¬¡ã«ãã³ã³ããã¹ããåé¢ããŠã2çªç®ã®ã¢ãã«ããè
«ããŠãããé£äººã«èµ·å ããåé¡ãçµéšããªãããã«ããããšã¯çã«ããªã£ãŠããŸãã åºæ¬çãªå®è£
ã§ã¯ãã³ã³ããã¹ãã¯ã°ããŒãã«ã§ããããããã©ã®ããã«åé¿ã§ãããã¯ããããŸããã
å²åŠè
ã®èµ·åã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
philosoperWorker :: Context -> Philosopher -> IO () philosoperWorker ctx philosopher = do atomically ctx (changePhilosopherActivity philosopher) threadDelay 5000 philosoperWorker ctx philosopher runPhilosophers :: IO () runPhilosophers = do ctx <- newContext
è§£éã«ã€ããŠå°ã
ã¢ãããã¯ã«ã¹ã¯ãªãããå®è¡ãããšã©ããªããŸããïŒ å®éã®ç°å¢ã«å¯Ÿããã·ããªãªã®è§£éãå§ãŸããŸãã ãã®æç¹ã§TVarã®äœæãšå€æŽãéå§ãããå²ãèŸŒã¿æ¡ä»¶ããã§ãã¯ã
ãããã©ã³ã¶ã¯ã·ã§ã³ã転éãããã³ã³ããã¹ãã§ã³ããããããããããŒã«ããã¯ãããŠåèµ·åãããã®ã
ã¢ãããã¯ã§ã ã ã¢ã«ãŽãªãºã ã¯æ¬¡ã®ãšããã§ãã
- äžæã®ãã©ã³ã¶ã¯ã·ã§ã³èå¥åãååŸããŸãã
- çŸåšã®ã³ã³ããã¹ãããããŒã«ã«ã³ããŒãååçã«åé€ããŸãã ããã§çãã³ã³ããã¹ãããã¯ãçºçããŸããããã¯ãéåžžã®ãã¥ãŒããã¯ã¹ã®ããã«åäœããMVarã䜿çšããŠè¡ãããŸãã
- ããŒã«ã«ã³ããŒã䜿çšããŠã¹ã¯ãªããã®è§£éãå®è¡ããçµæãåŸ
ã¡ãŸãã
- èšç®ãåéããã³ãã³ããåä¿¡ããå Žåã¯ãã¹ããªãŒã ããã°ããã¹ãªãŒãç¶æ
ã«ããŠãæé 1ã«é²ã¿ãŸãã
- çµæãåŸãããããããŒã«ã«ã³ããŒãšã³ã³ããã¹ãã®ç«¶åãã¢ãããã¯ã«ãã§ãã¯ããŸãã
- ç«¶åãèŠã€ãã£ãå Žåã¯ãã¹ããªãŒã ããã°ããã¹ãªãŒãç¶æ
ã«ããæé 1ã«é²ã¿ãŸãã
- ç«¶åããªããã°ããã¹ãŠãããŒã«ã«ã³ããŒãã¢ãããã¯ã«ã³ã³ããã¹ãã«åçµããŠããŸãã
- çµããã
ãã®èšç®ãããŒã«ã«ã³ããŒã§äœããããŠããéã«ãã³ã³ããã¹ãã倿Žãããå ŽåããããŸãã ãã®èšç®ã«é¢ä¿ããå°ãªããšã1ã€ã®TVarã倿Žããããšãã«ãç«¶åãçºçããŸãã ããã¯ãåã€ã³ã¹ã¿ã³ã¹ã«æ ŒçŽãããŠããäžæã®èå¥åã«ãã£ãŠç¢ºèªãããŸãã ãã ããèšç®ã§TVarã䜿çšãããªãã£ãå Žåãç«¶åã¯çºçããŸããã
ç§ãã¡ã®å®éã®ç°å¢ã¯ãç¶æ
ãšIOã¢ããã®ã¹ã¿ãã¯ã§ããç¹å®ã®
Atomicã¢ããã«ãã£ãŠè¡šçŸãããŸãã ç¶æ
ãšããŠ-ãã¹ãŠã®TVarã®ããŒã«ã«ã³ããŒïŒ
data AtomicRuntime = AtomicRuntime { ustamp :: UStamp , localTVars :: TVars } type Atomic a = StateT AtomicRuntime IO a
ãã®ã¢ããå
ã§ã¯ãçžäºã«ãã¹ãããã2ã€ã®æ§é ãè§£ããè§£éããŸãã
æãåºããšã
Freeåãš
STMFåã䜿çšããŠæ§ç¯ããã
STMLåã§ãã
Freeã®ã¿ã€ã
ã¯ãååž°çã§ãããã
ãå°ãé è³ã«ãªããŸãã 圌ã«ã¯2ã€ã®ãªãã·ã§ã³ããããŸãã
data Free fa = Pure a | Free (f (Free fa))
è§£éã¯åçŽãªãã¿ãŒã³ãããã³ã°ã«ãªããŸãã ã€ã³ã¿ãŒããªã¿ãŒã¯ããã©ã³ã¶ã¯ã·ã§ã³å
šäœã®å€ããŸãã¯ãã©ã³ã¶ã¯ã·ã§ã³ãåéããã³ãã³ããè¿ããŸãã
interpretStmf :: STMF a -> Atomic (Either RetryCmd a) interpretStmf (NewTVar a nextF) = Right . nextF <$> newTVar' a interpretStmf (ReadTVar tvar nextF) = Right . nextF <$> readTVar' tvar interpretStmf (WriteTVar tvar a next) = const (Right next) <$> writeTVar' tvar a interpretStmf Retry = pure $ Left RetryCmd interpretStml :: STML a -> Atomic (Either RetryCmd a) interpretStml (Pure a) = pure $ Right a interpretStml (Free f) = do eRes <- interpretStmf f case eRes of Left RetryCmd -> pure $ Left RetryCmd Right res -> interpretStml res runSTML :: STML a -> Atomic (Either RetryCmd a) runSTML = interpretStml
颿°
newTVar 'ãreadTVar'ãwriteTvar 'ã¯ããã©ã³ã¶ã¯ã·ã§ã³å€æ°ã®ããŒã«ã«ã³ããŒã§åäœããèªç±ã«å€æŽã§ããŸãã
runSTMLåŒã³åºãã¯ãå¥ã®é¢æ°
runSTMããäœæãããŸãããã®é¢æ°ã¯ãããŒã«ã«ã§å€æŽãããTVarã®ã³ã³ããã¹ãããã®ã°ããŒãã«ã³ããŒãšã®ç«¶åããã§ãã¯ãããã©ã³ã¶ã¯ã·ã§ã³ãåéãããã©ãããæ±ºå®ããŸãã
runSTM :: Int -> Context -> STML a -> IO a runSTM delay ctx stml = do (ustamp, snapshot) <- takeSnapshot ctx (eRes, AtomicRuntime _ stagedTVars) <- runStateT (runSTML stml) (AtomicRuntime ustamp snapshot) case eRes of Left RetryCmd -> runSTM (delay * 2) ctx stml Right res -> do success <- tryCommit ctx ustamp stagedTVars if success then return res else runSTM (delay * 2) ctx stml
ãã®é¢æ°ã¯èª¬æããã«æ®ããŸã
ãtryCommit颿°ã®
å®è£
æ¹æ³ã«ã€ããŠã¯è©³ãã説æããŸããã æ£çŽèšã£ãŠããŸãæé©ã§ã¯ãããŸããããããã¯å¥ã®èšäºã®ãããã¯ã§ãã
ãããã«
ç§ã®å®è£
ã§ã¯ããŸã æ°ã¥ããªããã°ãªããªã埮åŠãªç¹ãããã€ããããŸãã ãŸã æããã§ãªããã°ãååšããå¯èœæ§ãããããé©åãªåäœã®ããã«ãããå€ãã®ã±ãŒã¹ã確èªããå¿
èŠããããŸãããé©åãªSTMåäœãšèŠãªããããã®ã¯æç¢ºã§ã¯ãããŸããã ããããå°ãªããšããé£äºãããå²åŠè
ã®åé¡ã«ãããå€éšã®éãã¯æããã«ããŸããã§ãããã€ãŸããã¢ã€ãã¢ã¯æ©èœãããããæãèµ·ããããããšãã§ããŸãã ç¹ã«ãã©ã³ã¿ã€ã ã倧å¹
ã«æé©åããç«¶åã®è§£æ±ºãšããŒã«ã«ã³ããŒã®åé€ãããã€ã³ããªãžã§ã³ãã«ããããšãã§ããŸãã è§£éãšFree Monadã䜿çšããã¢ãããŒãã¯éåžžã«æè»ã§ããããšãããããã³ãŒãã¯ãèªèº«ã§ãããããã«ã¯ããã«å°ãããäžè¬çã«éåžžã«ç°¡åã§ãã ãŸããããã¯ãä»ã®èšèªã§ã®STMã®å®è£
ãžã®éãéããŠãããããåªããŠããŸãã
ããšãã°ãä»ãç§ã¯C ++ã§Free-monadic STMãç§»æ€ããŠããŸãããããã«ã¯ãã®èšèªã«ç¹æã®ç§èªèº«ã®å°é£ã䌎ããŸãã äœæ¥ã®çµæã«åºã¥ããŠã4æ
C ++ãã·ã¢2018äŒè°ã§ã¬ããŒããäœæãã誰ããããã蚪åããå Žåã¯ããã®ãããã¯ããã詳现ã«è°è«ã§ããŸãã