ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã»ã¹ãããã»ãã¤ã»ã¹ããã(Monad Transformers Step By Step)
èè ã®Martin Grabmülleræ°ã«è¨±å¯ãããã ãã¾ããã®ã§ã Haskellã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã®ãã¥ã¼ããªã¢ã«ã翻訳ãããã®ãå ¬éãã¾ãã
ã¿ã¤ãã誤訳ãããã°ã©ã ã®ãã¹çããã¾ãããã Twitterå®@bicycle1885ãã³ã¡ã³ãæ¬ã¾ã§ãé£çµ¡é ããã¨ãããããã§ãã
å ã®ããã¹ããããã°ã©ã ã¯ä»¥ä¸ã®ãªã³ã¯ããå¾ããã¾ãã
Monad Transformers Step by Step
- [2012/12/19] 誤ããå¤æ°è¨æ£ãã¾ãããid:qtamakiããããããã¨ããããã¾ãã
- [2014/6/19] 誤ãã2ç¹è¨æ£ãã¾ãããid:daimatzãããid:hitotakuchanããããããã¨ããããã¾ãã
Monad Transformers Step by Step
Martin Grabmüller Oct 16 2006
æ¦è¦(Abstract)
ãã®ãã¥ã¼ããªã¢ã«ã§ã¯ãHaskellã®ããã°ã©ã ã«å¾ã ã«æ©è½ã追å ãã¦ããããã«ã¯ãã©ã®ããã«ã¢ãããã©ã³ã¹ãã©ã¼ãã¼(Monad Transformer)ãå©ç¨ããããããã説æãã¾ãã
ããã¯ã¢ãããã©ã³ã¹ãã©ã¼ãã¼èªä½ã®ãå®è£ ãã«é¢ãããã®ã§ã¯ããã¾ããã ã¨ã¬ã¬ã³ãã§ã¹ãããªãã¦ãã¦ããªããã¤å¼·åãªHaskellããã°ã©ã ãæ¸ãããã«ãããã«ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ããå©ç¨ããããã«ã¤ãã¦ã®ãã¥ã¼ããªã¢ã«ã§ãã
åç´ãªå¼ãè©ä¾¡ããé¢æ°ããå§ããã¢ããã¹ã¿ã¤ã«ã«å¤ãã¦ãããã¢ãããã©ã³ã¹ãã©ã¼ãã¼ãæ§ç¯ãã¤ã¤ãã¨ã©ã¼å¦çãç°å¢æ¸¡ããç¶æ ããã°ãå ¥åºåã¨ãã£ãæ©è½ãå ãã¦ããã¾ãã
1 ã¤ã³ãããã¯ã·ã§ã³(Introduction)
ãã®ãã¥ã¼ããªã¢ã«ã§ã¯ãHaskellã®ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã¸ã¹ãããã»ãã¤ã»ã¹ãããã§ç´¹ä»ãã¦ããã¾ãã
ã¢ããã¯ãããã°ã©ã ãçµã¿ä¸ãã¦ããä¸ã§ãæè»ã§æ¡å¼µæ§ãæã¤é常ã«ã¨ã¬ã¬ã³ããªææ³ã§ãã ã¢ããã¯Haskellã®ãããªé 延è©ä¾¡é¢æ°åè¨èªã§ã¯ã¨ã¦ãèå³æ·±ããã®ã§ãç´ç²é¢æ°åã®ããã°ã©ã ã«å¯ä½ç¨ãçµ±åããããã¨ãã§ãã¾ãã ããã«ãã¢ããã使ã£ã¦ããã°ã©ã ãæ§ç¯ãã¦ãããã¨ã§ãã¡ãã£ã¨ããå®ç¾©ãããã°ãè²ã ãªã¢ã«ã´ãªãºã ã®å¿ è¦ãªè¨é²å¦çãè£å´ã®å¦çã®å¤ããé ããã¨ãã§ãã注ç®ãã¦ãã¢ã«ã´ãªãºã ã«éä¸ãããã¨ãã§ãã¾ãã
ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã¯ã¢ããã使ã£ãããã°ã©ãã³ã°ãããã«ä¾¿å©ã«ãã¦ããã¾ãã éã£ãã¢ãããåãã¢ãããé£çµããé¢æ°ã®ã©ã¤ãã©ãªãæä¾ãã¦ãããã®ã§ãå¿ è¦ãªã¢ãããã©ã³ã¹ãã©ã¼ãã¼ãçµã¿åããã¦ç¹è£½ã®ã¢ãããä½ããã¨ãã§ãã¾ãã ä¾ãã°ãç¶æ ã¨ã¨ã©ã¼å¦çãåããã¢ããã欲ãããªããStateTã¨ErrorTãµãã¤ã®ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ãé¸ãã§ãã¦çµã¿åãããã°ããã®ã§ãã ãã®ãã¥ã¼ããªã¢ã«ã®ç®çã¯ãã·ã³ãã«ãªé¢æ°ããå§ãããããã¹ãããã»ãã¤ã»ã¹ãããã§æ©è½ãæ¡å¼µãã¹ãè²ã ã¨ã¢ãããæã£ã¦åºãã¦ããæ§ãåªããç´¹ä»ãããã¨ã§ãã ãã®ãã¥ã¼ããªã¢ã«ã¯ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã®æ¦å¿µã®è£ã«æ½ãã çè«ã«ã¤ãã¦ã®ãã®ã§ã¯ããã¾ããããå®è£ ã«ã¤ãã¦ã®ãã®ã§ãããã¾ããï¼ãã¾ããã¨ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã使ãã®ã«å¿ è¦ãªãã®ã¯é¤ãï¼ã
ããã§ã¯ãHaskellã®ã¢ããã¯ã©ã¹ã¨ãdoè¨æ³ãªã©ã¨ãã£ããã¢ããã使ã£ãããã°ã©ãã³ã°ã®æ©è½ãåºç¤ã«ã¤ãã¦ã¯ç¥ã£ã¦ãããã¨ãæ³å®ãã¦ãã¾ããä»ã®ãã¨ã¯éä¸ã§è¿½ã 説æãã¦ããã¾ãã
ããã«ããHaskellã®ããã°ã©ã ã¯ç¾å¨ã®Haskell98æ¨æºã®ãã®ã§ã¯ãªãæ©è½ã使ã£ã¦ãã¾ããControl.Monad.Errorãªã©ã¯æ¨æºã©ã¤ãã©ãªã®ã¢ã¸ã¥ã¼ã«ã§ã¯ããã¾ããã ããããã¢ã¸ã¥ã¼ã«ã«ããé層çãªã¢ã¸ã¥ã¼ã«åãç´°ããå®è£ ãHaskell98ã®ç¯çã§ã¯ããã¾ããã ããããªãããããããæ¡å¼µã¯ç¾å¨ã®GHC[1]ã§ã¯ã¡ããã¨ãµãã¼ãããã¦ãã¾ãã ããã°ã©ã ã¯GHCã®ãã¼ã¸ã§ã³7.4.1ã§ç¢ºèªãã¦ãã¾ãã
ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã®ã¢ã¸ã¥ã¼ã«ã¯Mark P.Jonesã®è«æ[2]ã«ã¤ã³ã¹ãã¤ã¢ããã¦ãã¾ãããã®ä¸ã«ã¯ãã¨ã¦ãèªã¿ãããMonadããã°ã©ãã³ã°ã®ã¤ã³ãããã¯ã·ã§ã³ã¯ããã¾ããããã®ãã¥ã¼ããªã¢ã«ã»ã©ã¯å®è·µçã§ã¯ããã¾ããã
ãã®æç« ã¯æè¸çHaskell(Literate Haskell)ã®ã¹ã¯ãªããããAndres Lo Ìhã®lhs2TeXããªããã»ããµã使ã£ã¦å¤æããã¦ãã¾ãã ãã®ããã¹ãã¯GHCã§å®è¡å¯è½ã§ãã æè¸çHaskellã®ã½ã¼ã¹ãã¡ã¤ã« Transformers.lhs ã¯èè ã®ã¦ã§ããµã¤ãhttp://www.grabmueller.de/martin/www/pub/Transformers.en.htmlã«ããã¾ãã
ã³ã³ãã¥ã¼ã¿ãåã«ãã¦ãã®ãã¥ã¼ããªã¢ã«ãèªãã®ããã¹ãã§ãããã Haskellã®æ¨æºã©ã¤ãã©ãªãã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã®ã©ã¤ãã©ãªã«ããããããããªé¢æ°ã®èª¬æã調ã¹ãããåã調ã¹ããã§ããããã«ã§ãã ãã®ãã¥ã¼ããªã¢ã«ãå°å·ãã¦ãã¦ã§ããã©ã¦ã¶ã§ãªã³ã©ã¤ã³ã®ã©ã¤ãã©ãªã®ããã¥ã¡ã³ããéãã¦ãTransformersã¢ã¸ã¥ã¼ã«(ãã¨ã§èª¬æãã¾ã)ããã¼ããã¦ghciã§å¯¾è©±çã«:type(ãããã¯:t)ã§åã確èªããªããå®è¡ãã¦ã¿ãã®ãä¸çªã§ãããã
1.1 ããã°ã©ã ä¾(Example Program)
å®è¡ããä¾ã¨ãã¦ãã·ã³ãã«ãªããã°ã©ãã³ã°è¨èªã®ã¤ã³ã¿ã¼ããªã¿ããã®ãã¥ã¼ããªã¢ã«ãéãã¦ä½¿ãã¾ãã ãã¹ã¦ã®ã³ã¼ãã¯Transformersã¨ããã¢ã¸ã¥ã¼ã«ã«åãããã次ã®ãããªã³ã¼ããé ã«ããã¾ãã
module Transformers where import Control.Monad.Identity import Control.Monad.Error import Control.Monad.Reader import Control.Monad.State import Control.Monad.Writer import Data.Maybe import qualified Data.Map as Map
Control.Monadã§å§ã¾ãã¤ã³ãã¼ããããã¢ã¸ã¥ã¼ã«ã¯ããã®ä¸ã§å®ç¾©ãããã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã使ãã¨ãã ãå¿ è¦ã¨ãªãã¾ãã Data.Maybeã¢ã¸ã¥ã¼ã«ã¯Maybe aåã®ä»»æã®å¤ãæ±ãã®ã«ä¾¿å©ãªé¢æ°ãå®ç¾©ãã¦ãã¦ãData.Mapã¢ã¸ã¥ã¼ã«ã¯æéã®ããããå®ç¾©ãã¾ãã ãããã¯ãç°å¢ï¼å¤æ°-å¤ã®ãããã³ã°)ãå°ããªã¤ã³ã¿ã¼ããªã¿ã®ä¸ã§å®ç¾©ããã®ã«ä½¿ããã¾ãã
次ã®ãã¼ã¿åããã®è¨èªã®ä¸ã§ããã°ã©ã ãã¢ããªã³ã°ãããã®ã«ä½¿ããã¾ãã
type Name = String -- variable names (å¤æ°å) data Exp = Lit Integer -- expressions (å¼) | Var Name | Plus Exp Exp | Abs Name Exp | App Exp Exp deriving (Show) data Value = IntVal Integer -- values (å¤) | FunVal Env Name Exp deriving (Show) type Env = Map.Map Name Value -- mapping from names to values (å¤æ°åããå¤ã¸ã®ãããã³ã°)
Nameåã¯æ¨æºã®Stringåã®ãã ã®å¥åã§ãã æ®éçãªæååã§ãªããå¤æ°åã«ã¤ãã¦ã®è©±ã§ãããã¨ãæ確ã«ããæã«ä½¿ããã¾ãã Expãã¼ã¿åã¯ãæ´æ°ãªãã©ã«ã»å¤æ°ã»å ç®ã»Î»å¼(æ½è±¡)ã»é¢æ°é©ç¨ã¸ã®ã´ã¡ãªã¢ã³ããæã£ã¦ãã¾ãã è©ä¾¡ãããããã°ã©ã ã¯Expãã¼ã¿åããã§ãã¦ãã¦ãçµæã¯Valueåã§ãã Valueã¯æ´æ°ãé¢æ°(ã¯ãã¼ã¸ã£)ã§ãã FunValã®æ§æè¦ç´ ã§ããEnvã¯ãλæ½è±¡ãè©ä¾¡ãããç°å¢ã§ãã
ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ãç¨ããå ·ä½ä¾ã¯ãä¸ã«ç¤ºããå°ããªè¨èªã®ã¤ã³ã¿ã¼ããªã¿ãªã®ã§ãã¾ãã¯è©ä¾¡é¢æ°ãã¤ãããã¨ããå§ãã¾ãã ãã®é¢æ°ã¯ã¢ããã使ã£ã¦ãããããã種ã®ãåç §å®è£ ãã¨ãªã£ã¦ãã¾ãã ã¤ã³ã¿ã¼ããªã¿é¢æ°eval0ã¯ãåç´ã§ãã
eval0 :: Env -> Exp -> Value eval0 env (Lit i) = IntVal i eval0 env (Var n) = fromJust (Map.lookup n env) eval0 env (Plus e1 e2) = let IntVal i1 = eval0 env e1 IntVal i2 = eval0 env e2 in IntVal (i1 + i2) eval0 env (Abs n e) = FunVal env n e eval0 env (App e1 e2) = let val1 = eval0 env e1 val2 = eval0 env e2 in case val1 of FunVal env' n body -> eval0 (Map.insert n val2 env') body
æ´æ°ãªãã©ã«(Lit)ã¯ãValueåã«å ã¾ãã¦ãã®ã¾ã¾èªåèªèº«ã«è©ä¾¡ããã¾ãã å¤æ°(Var)ã¯ããã®ç°å¢ã§æç¸ããã¦ããå¤ã«è©ä¾¡ããã¾ãã fromJusté¢æ°ã¯Map.lookupé¢æ°ãMaybeãè¿ãã®ã§å¿ è¦ã§ãã ãã®é¢æ°ã§ã¯ãã©ãã«ãã©ã ãå¼ã§æç¸ããã¦ããªãå¤æ°ã使ããã¦ãã¾ãã¨ãã¨ã©ã¼ã¡ãã»ã¼ã¸ã¨å ±ã«ããã°ã©ã ã¯åæ¢ãã¾ãã å ç®(Plus)ã¯åç´ã«ï¼ã¤ã®ãªãã©ã³ããè©ä¾¡ãã¦ããã®åãè¿ãã¾ãã å ç®ã®ãªãã©ã³ãããçä¸æ¹ã§ãæ°å¤ã«ãªããªãã£ãããletå¼ã®ãã¿ã¼ã³ãããã³ã°ã¯å¤±æãããã¯ãã¨ã©ã¼ã¡ãã»ã¼ã¸ã¨å ±ã«ããã°ã©ã ã¯çµäºãã¦ãã¾ãã¾ãã æ½è±¡(Abs)ã¯ãè©ä¾¡ãããç°å¢ã«ãæãã¦é¢æ°å¤ã«è©ä¾¡ããã¾ãã é¢æ°é©ç¨(App)ã¯ãæåã«é¢æ°ã¨å¼æ°ãè©ä¾¡ããå ç®ã¨åãããã«å¦çããã¾ãã ä¸çªç®ã®å¼ã¯é¢æ°å¤ã«è©ä¾¡ãããªããã°ãªãããç°å¢ã«å¾ã£ã¦ãã®å é¨ãè©ä¾¡ããã¾ãã ããã§ä½¿ããã¦ããé¢æ°å¤ãå解ãã¦ããcaseå¼ã¯ãã¾ãå¥ã®ã¨ã©ã¼ãåãããããã¾ããã ãã®ãã¥ã¼ããªã¢ã«ã®å¾ã®æ¹ã§ã¯ãã¨ã©ã¼ã¢ããã使ã£ã¦ã¨ã©ã¼ãæ±ããã¨ã©ã¼ã®æ±ãããã£ã¨å¼·åã«ãã¦ãã¾ãã
eval0ã®å®ç¾©ã¯ããå°ãçããã§ãã¾ããä¾ãã°ãAppã®æã®letå¼ã¯åé·ããããã¾ããã ããããããã§ã®å®ç¾©ã¯ãå¾ã§å®ç¾©ãããã¢ããçã«ããã®ãç°¡åã«ãªãã¾ãã
12 + ((λx -> x)(4+2))
ãã®å¼ã¯ããã®ã¤ã³ã¿ã¼ããªã¿ã試ãã®ã«ã使ãã¾ãããããã«æ®ããå®ç¾©ãã¦ããã¾ãã
exampleExp = Lit 12 `Plus` (App (Abs "x" (Var "x")) (Lit 4 `Plus` Lit 2))
ä¾ãã°ã
> eval0 Map.empty exampleExp
ã¨ghciã«å ¥åããã°ãçãã¯
IntVal 18
ã¨ãªãã¾ãã
2 ã¢ãããã©ã³ã¹ãã©ã¼ãã¼(Monad Trasformers)
ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã使ãç®çã¯ãç¶æ ã»ã¨ã©ã¼ã»ç°å¢ã¨ãã£ãè¨ç®ã®å´é¢ãã³ã³ããã¼ã«ãããã¨ã§ãã ãã§ã«ããããã°ã©ã ãã¢ããã使ã£ã¦æ¸ããªããã®ã¯å°ã é¢åèãã§ãããä¸åº¦ãã£ã¦ãã¾ãã¨ã¢ããã絡ãé¨åãå ããããåã£ãããå¤æ´ãããããã®ã¯æ¯è¼çç°¡åã§ãã
ãã®ç¯ã§ã¯ã1.1ç¯ã®ããã°ã©ã ãã¢ããã使ã£ã¦æ¸ãç´ãããã¼ã¿åãé¢æ°å®ç¾©ãæ§ã ãªã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã®åãé¢æ°ã使ã£ã¦å¾ã ã«æ¡å¼µãã¦ããã¾ãã
2.1 ã¢ããã¹ã¿ã¤ã«ã«(Converting to Monadic Style)
ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã使ãã«ã¯ãé¢æ°ãã¢ããã¹ã¿ã¤ã«ã§è¡¨ç¾ããªããã°ãªãã¾ããã ããã¯ã¤ã¾ããé次å¦çãdoè¨æ³ã使ã£ãã¢ããæä½ã§æ¸ããé¢æ°ã®çµæã示ãããã«returné¢æ°ã使ãå¿ è¦ãããã¨ãããã¨ã§ãã
ã¾ããè©ä¾¡è£ ç½®ãå®ç¾©ãããã¢ãããå®ç¾©ãã¾ãã ä¸ã®Eval1 aãIdentity aåã®å¥åã¨ãã¦å®ç¾©ãã¾ããIdentityã¯ãControl.Monad.Identityããã¤ã³ãã¼ãããã¦ã¢ããã§ãæ³åãããéãä¸çªåç´ãªã¢ããããããã¾ããã Identityã¯ãæ¨æºçãªreturnã(>>=)ãã¢ããæä½ã®æ§ç¯ã®ããã«å®ç¾©ãã¦ãã¦ãrunIdentityé¢æ°ããã®ãããªæä½ãå®è¡ããããã«è¿½å ã§å®ç¾©ãã¦ãã¾ãã ãã以å¤ã«ã¯Identityã¢ããã¯ä½ããã¾ããã ããæå³ã§ããã®ã¢ããããåºç¤ãã¨ãã¦ä½¿ããå¨ããå¥ã®ã¢ããã§å ããã¨ãã§ãã¾ãã å¯èªæ§ã®ããããã runIdentityãå¼ã¶ããã®runEval1ãå®ç¾©ãã¦ãã¾ãã runEval1ã¯runIdentityãå¼ã³åºãã ãã§ãã
type Eval1 a = Identity a runEval1 :: Eval1 a -> a runEval1 ev = runIdentity ev
Eval1ã¢ããããã¨ã«eval0é¢æ°ãeval1ã¨ãã¦æ¸ããªããã¾ãã
eval1 :: Env -> Exp -> Eval1 Value eval1 env (Lit i) = return $ IntVal i eval1 env (Var n) = maybe (fail ("undefined variable: " ++ n)) return $ Map.lookup n env eval1 env (Plus e1 e2) = do IntVal i1 <- eval1 env e1 IntVal i2 <- eval1 env e2 return $ IntVal (i1 + i2) eval1 env (Abs n e) = return $ FunVal env n e eval1 env (App e1 e2) = do val1 <- eval1 env e1 val2 <- eval1 env e2 case val1 of FunVal env' n body -> eval1 (Map.insert n val2 env') body
ã¾ã注ç®ãã¹ããã¨ã¯ãLitã¨Absã®å ´åã«çµæã表ãããã«returné¢æ°ã使ã£ã¦ãããã¨ã§ãã (($)æ¼ç®åã¯çµåé ä½ãä½ãé¢æ°é©ç¨ã§ã主ã«ä¸¸æ¬å¼§()ãçãã«ä½¿ããã¾ãã) 次ã«ãVarã®å ´åã«ã¯fromJustã¯ããå¿ è¦ããã¾ããã ããã¯ãMap.lookupã¯ã©ããªã¢ããã®ä¸ã§ãfailé¢æ°ãå¼ã¶ã ãã§åãããã«ãªã£ã¦ãã¦ãããã§ã¯ããããã¾ããã¨å½ã¦ã¯ã¾ãããã§ãã (Identityã¢ããã®failé¢æ°ã¯ä¾å¤ãæããä¸æ¹ãMaybeã¢ããã®failé¢æ°ã¯Nothingãè¿ãã®ã§ãç°ãªãã¨ã©ã¼ã¡ãã»ã¼ã¸ãç¾ãã¾ãã)
PlusãAppã®å ´åã¯å é¨ã®å¼ãdoè¨æ³ã§è©ä¾¡ããçµæãå¤æ°ã«æç¸ãã¦ãã¾ãã Plusã§ã¯çµæã¯returnã使ã£ã¦è¿ããã¾ãããAppã§ã¯é¢æ°å¤ã¯ä¸ã®eval0é¢æ°ã®ããã«ããã«èå¥ããã¾ãã
ãã®ã¤ã³ã¿ã¼ããªã¿ã試ãã«ã¯ãeval1ããµã³ãã«ã®å¼exampleExpã«é©ç¨ãã¦å¾ãããã¢ããã®ã¢ã¯ã·ã§ã³ãè©ä¾¡ããå¿ è¦ãããã¾ãã ããã¯åã«å®ç¾©ããrunEval1ãå¼ã¹ã°å¤§ä¸å¤«ã§ãã
runEval1 (eval1 Map.empty exampleExp)
ã¨ããã°ã
IntVal 18
ã¨ãªãã¾ãã
è¦ç´ããã°ãreturné¢æ°ã使ã£ã¦é¢æ°ã®çµæãè¿ããã¨ã¨ãdoè¨æ³ã(>>=)ã(>>)é¢æ°ãã¤ãã£ã¦ã¢ããã¢ã¯ã·ã§ã³ã®é次ãè¡ããã¨ã®ï¼ã¤ããã¢ããã¸ã®å¤æã¯æãç«ã£ã¦ãã¾ãã
NOTE
eval1ã®åã¯ã以ä¸ã®ããã«ä¸è¬åã§ãã¾ãã
eval1 :: Monad m => Env -> Exp -> m Value
ããã¯ãreturnã¨ãdoè¨æ³ã«é ããã(>>=)以å¤ã«ã¯ãã©ããªã¢ããæä½ãè¡ã£ã¦ããªãããã§ãã ããããã°ã©ããªã¢ããã®æèã§ãeval1ã使ããã¨ãã§ãã
runEval1 (eval1 Map.empty exampleExp)
ã¨ãã代ããã«ghciã§
eval1 Map.empty exampleExp
ã¨æ¸ãã¾ãã ããã¯ãIOã¢ããã®å é¨ã§å¼ãå®è¡ãã¾ããã¤ã³ã¿ã¼ããªã¿ã¯å é¨çã«printé¢æ°ã使ã£ã¦ãã¾ããããã®é¢æ°ã¯IOã¢ããã®å é¨ã§ãã使ããªãããã§ãã ããã¯å¬ãããã¨ãããã¾ãããç¹å®ã®ã¢ããã«åºæã®æä½ã使ããã¨ãå¤ãã§ãããããç¹å®ã®ã¢ããã«æä½ã¯ç¸ããã¦ãã¾ãã¾ãã
2.2 ã¨ã©ã¼å¦çãå ãã(Adding Error Handling)
ä»ã¾ã§è¦ã¦ããããã«ãç¾ç¶ã®è©ä¾¡é¢æ°ã¯é¨åç(partial)ã§ãã ä¾ãã°æç¸ããã¦ããªãå¤æ°ãåã¨ã©ã¼ãããå¼ãªã©ãå ¥åã«ãã£ã¦ã¯ã¨ã©ã¼ã¡ãã»ã¼ã¸ã¨å ±ã«æ¢ã¾ã£ã¦ãã¾ãã¾ãã (訳注: é¨åé¢æ°ã«ã¤ãã¦ã¯ãPartial Function Considered Harmfulãåèã«ãªãã¾ã)
ãã¼ã«ã«ã®ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã©ã¤ãã©ãªã«ããErrorTã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã使ãã°ãEval1ã¢ãããåºã«ãã¦Eval2ã¸æ¡å¼µã§ãã¾ãã
type Eval2 a = ErrorT String Identity a
ErrorTã®Stringåå¼æ°ã¯ä¾å¤ã®åã§ãã¨ã©ã¼ã®ç¶æ ã示ãããã«ä½¿ãããå¤ã§ãã ããã§ã¯ç°¡åã®ããã«Stringã使ãã¾ãããå®éã®å®è£ ã§ã¯ã³ã³ãã¤ã©ã ã¨ã½ã¼ã¹ã³ã¼ãã®ä½ç½®ã ã¨ããã¦ã§ãã¢ããªã±ã¼ã·ã§ã³ã ã¨ã¿ã¤ã ã¹ã¿ã³ãã ã¨ããããã¨è¯ãããããã¾ããã
Eval2ã¢ããå ã§ã®è¨ç®ãå®è¡ããé¢æ°ã¯ãï¼ã¤ç°ãªãç¹ãããã¾ãã ã²ã¨ã¤ç®ã¯è©ä¾¡ã®çµæãEither String aåã§ãLeft sã ã¨ã¨ã©ã¼ãèµ·ãããã¨ãã¨ã©ã¼ã¡ãã»ã¼ã¸sã§ç¤ºããRight rã ã¨è©ä¾¡ãæåãããã¨ãçµærã§è¡¨ãã¾ãã äºã¤ç®ã¯ãrunErrorTé¢æ°ãä¸ããããè¨ç®ã«å¯¾ãã¦å¼ã³åºããIdentityã®è¨ç®ãè¿ãããä»åº¦ã¯ãããrunIdentityã使ã£ã¦è©ä¾¡ãããã¨ãããã¨ã§ãã
runEval2 :: Eval2 a -> Either String a runEval2 ev = runIdentity (runErrorT ev)
ãã¦ããeval1é¢æ°ã®åãåç´ã«æ¸ãæãããã¨ãã§ãã¦ã次ã®ãã¼ã¸ã§ã³(eval2a)ã示ãã¾ãã
eval2a :: Env -> Exp -> Eval2 Value eval2a env (Lit i) = return $ IntVal i eval2a env (Var n) = maybe (fail ("undefined variable: " ++ n)) return $ Map.lookup n env eval2a env (Plus e1 e2) = do IntVal i1 <- eval2a env e1 IntVal i2 <- eval2a env e2 return $ IntVal (i1 + i2) eval2a env (Abs n e) = return $ FunVal env n e eval2a env (App e1 e2) = do val1 <- eval2a env e1 val2 <- eval2a env e2 case val1 of FunVal env' n body -> eval2a (Map.insert n val2 env') body
ãã®ãã¼ã¸ã§ã³ã¯ä¸ã§å®ç¾©ãããrunEval2é¢æ°ã使ã£ã¦å®è¡ã§ãã¾ãã ãã®é¢æ°ããµã³ãã«ã®å¼ã«é©ç¨ããã¨ãçµæã¯Rightæ§ç¯åã«å ã¾ãã¦ããç¹ã®ã¿ãå¤ãã£ã¦ãã¾ãã
runEval2 (eval2a Map.empty exampleExp) => Right (IntVal 18)
ãããæ®å¿µãªãã¨ã«ãæ£ãããªãå¼ãä¸ããããã¨ErrorTãã©ã³ã¹ãã©ã¼ãã¼ã®ã¨ã©ã¼å ±åã¯ä½¿ããã¾ããã ãã£ã¨æç¨ãªã¨ã©ã¼ã¡ãã»ã¼ã¸ãåãããã«ã¯æ¹è¯ãå¿ è¦ã§ãã
eval2b :: Env -> Exp -> Eval2 Value eval2b env (Lit i) = return $ IntVal i eval2b env (Var n) = maybe (fail ("undefined variable: " ++ n)) return $ Map.lookup n env eval2b env (Plus e1 e2) = do e1' <- eval2b env e1 e2' <- eval2b env e2 case (e1', e2') of (IntVal i1, IntVal i2) -> return $ IntVal (i1 + i2) _ -> throwError "type error" eval2b env (Abs n e) = return $ FunVal env n e eval2b env (App e1 e2) = do val1 <- eval2b env e1 val2 <- eval2b env e2 case val1 of FunVal env' n body -> eval2b (Map.insert n val2 env') body _ -> throwError "type error"
ããã§ãæ£ãããªãå¼ãè©ä¾¡ãããã¨ããã¨ãLeftæ§ç¯åã«å ã¾ããã¨ã©ã¼ã¡ãã»ã¼ã¸ãåºã¾ãã ããã¦ãè©ä¾¡çµæã«å¯¾ãã¦ãã¿ã¼ã³ãããã³ã°ããããã¨ã§ãé常ã®çµæã¨ã¨ã©ã¼ã®çµæãåºå¥ãããã¨ãã§ãã¾ãã
runEval2 (eval2b Map.empty (Plus (Lit 1) (Abs "x" (Var "x")))) => Left "type error"
(訳注: åæã§ã¯ runEval2 (eval2a Map.empty (Plus (Lit 1) (Abs "x" (Var "x"))))
ã¨ãªã£ã¦ããããèè
ã®æå³ã¯æããeval2aã§ãªãeval2b)
ãããã¡ãã£ã¨å¾ ã£ã¦ãã ããï¼ Map.lookupã«ã¤ãã¦ã¯ã©ãã§ãããï¼ Nothingãè¿ããã©ããã確ããã¦ãé©åãªã¨ã©ã¼ã¡ãã»ã¼ã¸ãçæããã¹ãã§ã¯ãªãã§ããããï¼ åè¿°ããã¨ãããMap.lookupã¯ä»»æã®ã¢ããã§çµæãè¿ãã¾ãããControl.Monad.Errorã¢ã¸ã¥ã¼ã«ã¯ããã«åãããã«å¿ è¦ãªå®ç¾©ãæä¾ãã¦ãã¾ãã
runEval2 (eval2b Map.empty (Var "x")) => Left "Data.Map.lookup: Key not found"
(訳注: containers-0.5.2.1
ã®å®éã®Data.Map.lookupã®å®ç¾©ã¯ãMaybeã¢ãããè¿ãããã«ãªã£ã¦ããããªã®ã§ãä¸è¨ã®ã¨ã©ã¼ã¡ãã»ã¼ã¸ã¯ãå®éã«ã¯ Left "undefined variable: x"
ã¨ãªã)
eval2bé¢æ°ãããã¡ãã£ã¨ãã調ã¹ã¦ã¿ãã°ãdoå¼ã®å é¨ã®ã¢ããçµåã§ã¯ãã¿ã¼ã³ãããã³ã°ã失æããã¨ãã«failé¢æ°ãå¼ã³åºãã¨ãããã¨ããã¾ã使ãã¨ããã£ã¨çãï¼è¯ãï¼ï¼ã§ãããã¨ããããã¾ãã ããã¦ãä»ã¾ã§è¦ã¦ããããã«ãfailé¢æ°ã¯æã£ãã¨ããã«åãã¦ããã¾ãã
eval2c :: Env -> Exp -> Eval2 Value eval2c env (Lit i) = return $ IntVal i eval2c env (Var n) = maybe (fail ("undefined variable: " ++ n)) return $ Map.lookup n env eval2c env (Plus e1 e2) = do IntVal i1 <- eval2c env e1 IntVal i2 <- eval2c env e2 return $ IntVal (i1 + i2) eval2c env (Abs n e) = return $ FunVal env n e eval2c env (App e1 e2) = do FunVal env' n body <- eval2c env e1 val2 <- eval2c env e2 eval2c (Map.insert n val2 env') body
ãã®é¢æ°ã®é£ç¹ã¯ãã¨ã©ã¼ã¡ãã»ã¼ã¸ã"pattern match failure"(ãã¿ã¼ã³ãããã³ã°å¤±æ)ã¨ããè¨ããªããã¨ã§ãã©ããã¦ãã¿ã¼ã³ãããã³ã°ã失æããã®ãã«ã¤ãã¦å ·ä½çãªæ å ±ã¯ä½ããªãã¨ãããã¨ã§ãã ã§ãã®ã§ããã£ã¨è¯ãã¨ã©ã¼ã¡ãã»ã¼ã¸ã欲ãããªããèªåã§throwErrorãããæ¹ãè¯ãã§ãã ãããã¨ã©ã¼å¦çè©ä¾¡ãããæçµãã¼ã¸ã§ã³ã§ãã
eval2 :: Env -> Exp -> Eval2 Value eval2 env (Lit i) = return $ IntVal i eval2 env (Var n) = case Map.lookup n env of Nothing -> throwError ("unbound variable: " ++ n) Just val -> return val eval2 env (Plus e1 e2) = do e1' <- eval2 env e1 e2' <- eval2 env e2 case (e1', e2') of (IntVal i1, IntVal i2) -> return $ IntVal (i1 + i2) _ -> throwError "type error in addition" eval2 env (Abs n e) = return $ FunVal env n e eval2 env (App e1 e2) = do val1 <- eval2 env e1 val2 <- eval2 env e2 case val1 of FunVal env' n body -> eval2 (Map.insert n val2 env') body _ -> throwError "type error in application"
NOTE
Control.Monad.Errorã¢ã¸ã¥ã¼ã«ã¯throwErrorã§çããã¨ã©ã¼ãæã¾ããããã«ãå¥ã®é¢æ°ãæä¾ãã¦ãã¾ãã ããããcatchError :: m a -> (e -> m a) -> m aã§ãä»»æã®ã¨ã©ã¼ã¢ããã«ä½¿ãã¾ãã å±æçãªã¨ã©ã¼å¦çã«ãã¨ã©ã¼ãä¸ä½ã«æ¸¡ããã¨ã«ã使ãã¾ãã
2.3 ç°å¢ãé ã(Hiding the Environment)
è©ä¾¡é¢æ°ã®å®ç¾©ããã£ã¨ãããã®ã«ããä¸ã¤ã®æ¹æ³ã¯ããã¹ã¦ã®é¢æ°å®ç¾©ã¨å¼ã³åºãããç°å¢ãé ããã¨ã§ãã ç°å¢ãå±éãããå ´æã¯ä¸ã«æï¼é¢æ°é©ç¨ï¼ã ããå®éã«ä½¿ãããå ´æã¯äºã¶æï¼å¤æ°ã¨ã©ã ãå¼ï¼ã ããªã®ã§ãä»ã®å ´æã§ã¯ç°å¢ãé ãã°ã³ã¼ãã®éãæ¸ãããã¨ãã§ãã¾ãã ããã¯ãªã¼ãã¼ã¢ãããå®è£ ããããã«ReaderTã¢ãããã©ã³ã¹ãã©ã¼ãã¼ãå ããã°å®ç¾ã§ãã¾ãã Readerã¢ããã¯ãå¤ããã®ä¸ã®ãã¹ã¦ã®è¨ç®ã«æ¸¡ãã¾ãã ãã®å¤ã¯å å´ã®è¨ç®ããèªããã¨ãã§ããå ¥ãåã«ãªã£ãè¨ç®ã®ä¸ã§ã¯æ¹å¤ãããã¨ãã§ãã¾ãã ç¶æ (State)ã¢ããï¼2.4ç¯ã§ç´¹ä»ããã¾ãï¼ã¨ç°ãªããã«ãã»ã«åãããè¨ç®ã¯ä¸ä½ã®è¨ç®ã§ä½¿ãããå¤ãæ¹å¤ãããã¨ãã§ãã¾ããã
以åã®ã¢ããåã«ãReaderTæ§ç¯åã§å ããã¨ããå§ãã¾ãã
type Eval3 a = ReaderT Env (ErrorT String Identity) a
å®è¡é¢æ°runEval3ã¯ãåæç°å¢ãä¸ããå¿ è¦ãããã®ã§å°ãå¤æ´ããªããã°ãªãã¾ããã è©ä¾¡é¢æ°ããç°å¢å¼æ°ãåããã¨ãç®çã§ãã
runEval3 :: Env -> Eval3 a -> Either String a runEval3 env ev = runIdentity (runErrorT (runReaderT ev env)) eval3 :: Exp -> Eval3 Value eval3 (Lit i) = return $ IntVal i eval3 (Var n) = do env <- ask case Map.lookup n env of Nothing -> throwError ("unbound variable: " ++ n) Just val -> return val eval3 (Plus e1 e2) = do e1' <- eval3 e1 e2' <- eval3 e2 case (e1', e2') of (IntVal i1, IntVal i2) -> return $ IntVal (i1 + i2) _ -> throwError "type error in addition" eval3 (Abs n e) = do env <- ask return $ FunVal env n e eval3 (App e1 e2) = do val1 <- eval3 e1 val2 <- eval3 e2 case val1 of FunVal env' n body -> local (const (Map.insert n val2 env')) (eval3 body) _ -> throwError "type error in application"
ãµã³ãã«ãå®è¡ãããªãã以ä¸ã®ããã«è©ä¾¡ãã¦ãã ããã
runEval3 Map.empty (eval3 exampleExp)
ç¾å¨ã®ç°å¢ãå¿ è¦ã«ãªãå ´æã§ã¯ãReaderã¢ããã®é ããç¶æ ããaské¢æ°ã使ã£ã¦å¼ãåºãã¾ãã é¢æ°é©ç¨ã®å ´åã§ã¯ãlocalé¢æ°ãå帰çå¼ã³åºãã®ç°å¢ãå¤æ´ããã®ã«ä½¿ããã¦ãã¾ãã localã¯(r -> r) -> m a -> m aåãæã£ã¦ãã¦ãç¾å¨ã®ç°å¢ããã第äºå¼æ°ã«ããå ¥ãåã«ãªã£ãè¨ç®ã§ä½¿ãããç°å¢ã¸ã®ããããããé¢æ°ã渡ãå¿ è¦ãããã¾ãã ãã®å ´åã§ã¯ãå ¥ãåã«ãªã£ãç°å¢ã¯ç¾å¨ã®ç°å¢ã«ç´æ¥ä¾åãã¦ããªãã®ã§ãconsté¢æ°ã«æ¸¡ãã ãã§ãã
NOTE
askã«å ããasksé¢æ°ãäºãå®ç¾©ããã¦ãã¦ç°å¢ããå¤ã¸ã¨ãããã³ã°ããé¢æ°ãåãã¾ãã ããã¯ãã¬ã³ã¼ãã»ã¬ã¯ã¿ã¼é¢æ°(record selector function)ã«asksãé©ç¨ãã¦ç°å¢ã®ããããã®æ§æè¦ç´ ãåãåºãã®ã«ä½¿ããã¨ãã§ãã¾ãã (訳注ï¼ã¬ã³ã¼ãã»ã¬ã¯ã¿ã¼é¢æ°ã¨ã¯ããã¼ã¿åãrecord syntaxã§å®ç¾©ããéã«ã³ã³ãã¤ã©ãèªåçã«ä½ããã£ã¼ã«ãã®å¤ãåå¾ããé¢æ°ã®ãã¨ã§ãã)
2.4 ç¶æ ãå ãã(Adding State)
éè¦ãªã¢ããã®å¿ç¨ä¾ã¨ãã¦ãç´ç²é¢æ°åã®ããã°ã©ã ã«å¤æ´å¯è½(mutable)ãªç¶æ ãå¯è½ã«ãããã¨ãæãããã¾ãã ããã¯Stateã¢ãããç¨ããã°ãããåæç¶æ ã®è¨å®ã»ç¾å¨ã®ç¶æ ã®åãåããã»å¤æ´ã¨ãã£ãæä½ãæä¾ãã¦ããã¦ãã¾ãã
ä¾ã¨ãã¦ããã®ã¤ã³ã¿ã¼ããªã¿ã«ãããã¡ã¤ãªã³ã°æ©è½ãä»ã足ãããã¨ãã¾ãããã æãå å´ã®ã¢ããï¼Identity)ãStateTæ§ç¯åã§å ãã§æ°ããã¢ãããå®ç¾©ãã¾ãã (Stateã¢ããã¨Errorã¢ããã«é¢ãã¦ã¯ãå¾ã§è¦ãããã«æ§ç¯åã®é çªãåé¡ã«ãªãã¾ãã) ä¾ã§ã¯åç´ãªæ´æ°å¤ãç¶æ ã¨ãã¦ä¿æãã¾ãããã©ããªãã¼ã¿åã®å¤ã§ãå¯è½ã§ãã é常ã¯ãç®ä¸ã®ä»äºã«å¿ è¦ååãªç¶æ ããè¨é²ã¨ãã¦ä¿æãããã¨ã«ãªãã¾ãã
type Eval4 a = ReaderT Env (ErrorT String (StateT Integer Identity)) a
runEval4é¢æ°ã®è¿ãå¤ã®åã¯å¤ããã¾ãã æçµçãªç¶æ ãè©ä¾¡çµæ(ã¨ã©ã¼ãè¨ç®å¤)ã¨ä¸ç·ã«è¿ãããããã§ãã ããã«ãåæç¶æ ã追å ã®å¼æ°ã§æ¸¡ããä¾ãã°å¥ã®è¨ç®ã®æå¾ã®ç¶æ ããå度è¨ç®ãå§ãããªã©ãã§ããããã«ãæè»æ§ãæããã¦ãã¾ãã
runEval4 :: Env -> Integer -> Eval4 a -> (Either String a, Integer) runEval4 env st ev = runIdentity (runStateT (runErrorT (runReaderT ev env)) st)
åç´ãªä¾ã¨ãã¦ãè©ä¾¡ã®ã¹ãããæ°ãæ°ããã ãã«ãããã¨æãã¾ãã ã¤ã¾ããeval4é¢æ°ãå¼ãã åæ°ã§ãã ç¶æ ã®å¤æ´ã¯ããã¹ã¦å°ããªè£å©çé¢æ°tickã®ä¸ã§èµ·ããé ãããç¶æ ãè¨ç®ããåãåºããã«ã¦ã³ã¿ã¼ãå¢ããã¦ãç¶æ ãæ»ãã¾ãã ãã®å ã®ç¯ã§åå©ç¨ããã¤ãããªã®ã§ããã¡ããtickã®åã¯Eval4 ()ã§ã¯ããã¾ããã ã§ãã®ã§ãä¸ã§tickã使ãããã¢ããã¯ç¶æ ã¢ãã(訳注:ãã®å ´åMonadStateåã¯ã©ã¹ã®ãã¨)ã§ããã®ã¢ããã®ä¸ã§æä½ãããç¶æ ã¯(+)æ¼ç®åã使ããããã«æ°å¤ã«ããã¨è¨ãã«ã¨ã©ãã¾ãã
tick :: (Num s, MonadState s m) => m () tick = do st <- get put (st + 1)
ããããã®å ´åã§tické¢æ°ã®å¼ã³åºããå ããã°ãé©ç¨ã®åæ°ãæ°ãããã¨ãã§ãã¾ãã
eval4 :: Exp -> Eval4 Value eval4 (Lit i) = do tick return $ IntVal i eval4 (Var n) = do tick env <- ask case Map.lookup n env of Nothing -> throwError ("unbound variable: " ++ n) Just val -> return val eval4 (Plus e1 e2) = do tick e1' <- eval4 e1 e2' <- eval4 e2 case (e1', e2') of (IntVal i1, IntVal i2) -> return $ IntVal (i1 + i2) _ -> throwError "type error in addition" eval4 (Abs n e) = do tick env <- ask return $ FunVal env n e eval4 (App e1 e2) = do tick val1 <- eval4 e1 val2 <- eval4 e2 case val1 of FunVal env' n body -> local (const (Map.insert n val2 env')) (eval4 body) _ -> throwError "type error in application"
ãµã³ãã«ãè©ä¾¡ããã¨ã
(Right (IntVal 18), 8)
ã¨åºã¾ããããã¯è©ä¾¡ãæåãã¦æ´æ°18ãè¿ããç°¡ç´ã8ã¹ãããã ã£ãã¨ãããã¨ã表ãã¦ãã¾ãã
NOTE
Eval4ã¢ããã®åã次ã®ããã«å¤ããï¼StateTã¨ErrorTãå ¥ãæ¿ããï¼ã¨ãã¢ããã®è§£éãå¤ããã¾ãã
type Eval4' a = ReaderT Env (StateT Integer (ErrorT String Identity)) a
çµæï¼ã¨ã©ã¼ãå¦ãï¼ã¨ç¶æ ãè¿ã代ããã«ãã¨ã©ã¼ãçµæã¨æçµçãªç¶æ ããè¿ãã¾ãã ããã¯å¯¾å¿ããå®è¡é¢æ°ã®åãããåããã§ãããã
runEval4' :: Env -> Integer -> Eval4' a -> (Either String (a, Integer)) runEval4' env st ev = runIdentity (runErrorT (runStateT (runReaderT ev env) st))
æçµçãªç¶æ ã«ã¯é¢ä¸ããªãã®ã§ãReaderã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã®ä½ç½®ã¯åé¡ã«ã¯ãªãã¾ããã
NOTE
Stateã¢ããã¯getsé¢æ°ãæä¾ãã¦ãããçµæãè¿ãåã«ç¶æ ã«å¯¾ãã¦é¢æ°ãé©ç¨ãã¾ãã å é¨ç¶æ ã«é¢æ°ãé©ç¨ãããã¨ã«ãã£ã¦ç¶æ ãå¤æ´ããmodifyé¢æ°ãããã¾ãã
2.5 ãã°ãå ãã(Adding Logging)
ããã§è¿°ã¹ãéå ·ç®±ã«ããæå¾ã®ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã¯WriteTã§ãã ããæå³ReaderTã®å¯¾ã«ãªããã®ã§ããWriterTãæä¾ããé¢æ°ã¯ã渡ãããå¤ãç¨ãããã®ã§ã¯ãªããè¨ç®çµæã«å¤ã追å ãããã®ã ããã§ãã
type Eval5 a = ReaderT Env (ErrorT String (WriterT [String] (StateT Integer Identity))) a
StateTã®å ´åã¨åæ§ã«ãçµæãåºåãããã®ãªã®ã§WriterTã¯ErrorTã¨å¹²æ¸ãã¾ãã ErrorTã¨WriterTã®é çªã«ãã£ã¦ãã¨ã©ã¼ãèµ·ããã¨ãã«ãçµæã(訳注:Writerã¢ããã®)å¤ãè¿ããã©ãããå¤ããã¾ãã æ¸ãåºãããå¤ãã¯æååã®ãªã¹ãã§ãã WriterTã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã®ããã¥ã¡ã³ããèªãã¨ãæ¸ãã ãããå¤ã®åã¯ã¢ãã¤ã(Monoid)åã¯ã©ã¹ã®ã¡ã³ãã¼ã«å¶éããããã¨ããããã§ãããã ãã®ãã¨ã¯ããã®ã¯ã©ã¹ã®ã¡ã½ããã¯å é¨çã«åæå¤ãæ§æããããæ¸ãåºãããå¤ãåæãããããã®ã«ä½¿ãããããå¿ è¦ãªãã¨ã§ãã
å®è¡é¢æ°ã¯å ã»ã©ã¨åãããã«æ¡å¼µããã¾ãã
runEval5 :: Env -> Integer -> Eval5 a -> ((Either String a, [String]), Integer) runEval5 env st ev = runIdentity (runStateT (runWriterT (runErrorT (runReaderT ev env))) st)
è©ä¾¡é¢æ°ã§ã¯ãè©ä¾¡ä¸ã«ééããå¤æ°åãæ¸ãåºããã¨ã«ãã£ã¦ãWriterã¢ããã®ä½¿ãæ¹ã説æãã¦ãã¾ãã
eval5 :: Exp -> Eval5 Value eval5 (Lit i) = do tick return $ IntVal i eval5 (Var n) = do tick tell [n] env <- ask case Map.lookup n env of Nothing -> throwError ("unbound variable: " ++ n) Just val -> return val eval5 (Plus e1 e2) = do tick e1' <- eval5 e1 e2' <- eval5 e2 case (e1', e2') of (IntVal i1, IntVal i2) -> return $ IntVal (i1 + i2) _ -> throwError "type error in addition" eval5 (Abs n e) = do tick env <- ask return $ FunVal env n e eval5 (App e1 e2) = do tick val1 <- eval5 e1 val2 <- eval5 e2 case val1 of FunVal env' n body -> local (const (Map.insert n val2 env')) (eval5 body) _ -> throwError "type error in application"
2.6 IOã¯ã©ãããã®ï¼(What about I/O?)
ããã¾ã§ã®ã¨ãããããéè¦ãªé¢ãèæ ®ãã¦ãã¾ãããå ¥åã¨åºåã§ãã ã©ã®ããã«ãã¦ããã¾ã§ã«éçºãã¦ããã¢ããã®å®ç¾©ã«ãå ¥åºåãå°å ¥ããã°ããã§ããããã IOã¢ãããã©ã³ã¹ãã©ã¼ãã¼ãå®ç¾©ãããã¨ã¯ã§ãã¾ããã ãªããªããHaskellã®IOæä½ã®å®è¡ã¯ä»ã®é¢æ°ãã¢ããã«åæã«å ¥ãåã«ãã¦ã¯ãªãããIOã¢ããã§ã®ã¿å¯è½ã«ãªã£ã¦ããããã§ãã 幸éãªãã¨ã«ãã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã®ã©ã¤ãã©ãªã¯ãç§ãã¡ãçµã¿ä¸ãã¦ãããã®ã«ç°¡åã«IOæä½ãå°å ¥ããä¸å°ãæä¾ãã¦ããã¦ãã¾ãã åã«Identityã®ä»£ããã«IOã使ãã°ããã®ã§ãï¼ ããã¯ãIdentityãåºã«ãªãã¢ããã§ãä»ã¾ã§è¦ã¦ããããã«ããã®ã¢ããã®ã¢ã¯ã·ã§ã³ãè©ä¾¡ããrunIdentityé¢æ°ã¯ããã¤ã§ãä¸çªæå¾ã«é©ç¨ããã¦ããããã§ãã
type Eval6 a = ReaderT Env (ErrorT String (WriterT [String] (StateT Integer IO))) a
runEval6ãè¿ãåã¯ãIOæ§ç¯åã«ãã£ã¦å ã¾ãã¦ãã¾ãã Eval6ã®è¨ç®ãå®è¡ãããã¨ã¯ç´æ¥çã«çµæãåºãã®ã§ã¯ãªããçµæãå¾ãã«ã¯å®è¡ããªããã°ãªããªãIOè¨ç®ãè¿ãã¾ãã
runEval6 :: Env -> Integer -> Eval6 a -> IO ((Either String a, [String]), Integer) runEval6 env st ev = runStateT (runWriterT (runErrorT (runReaderT ev env))) st
eval6é¢æ°ã§ã¯ãã¡ãã£ã¨ããã²ã¨æéã§IOæä½ãè¡ãã¾ãã ããã«ã¯ãliftIOé¢æ°ã使ã£ã¦æä½ãå¼ã³åºãå¿ è¦ããããããã§IOè¨ç®ãç¾å¨å®è¡ä¸ã®ã¢ããã«æã¡ä¸ãããã¨ãã§ãã¾ãã ä¾ã¨ãã¦ãæ´æ°å®æ°ãè©ä¾¡ããã度ã«ããªã³ããããã¨ã«ãã¾ããï¼ãããè¯ãæ¹æ³ã ã¨ã¯æãã¾ããããè¦ç¹ã説æã§ãã¾ãããè¯ããããã°ã®ãã¯ããã¯ã«ãªããã¨ãããã¾ããï¼
eval6 :: Exp -> Eval6 Value eval6 (Lit i) = do tick liftIO $ print i return $ IntVal i eval6 (Var n) = do tick tell [n] env <- ask case Map.lookup n env of Nothing -> throwError ("unbound variable: " ++ n) Just val -> return val eval6 (Plus e1 e2) = do tick e1' <- eval6 e1 e2' <- eval6 e2 case (e1', e2') of (IntVal i1, IntVal i2) -> return $ IntVal (i1 + i2) _ -> throwError "type error in addition" eval6 (Abs n e) = do tick env <- ask return $ FunVal env n e eval6 (App e1 e2) = do tick val1 <- eval6 e1 val2 <- eval6 e2 case val1 of FunVal env' n body -> local (const (Map.insert n val2 env')) (eval6 body) _ -> throwError "type error in application"
3 çµè«(Conclusion)
ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã¯é¢æ°åããã°ã©ãã¼ã®æã¦ãå¼·åãªãã¼ã«ã§ãã ãã®ãã¥ã¼ããªã¢ã«ã§ã¯ãç¾å¨ã®Haskellã®å®è£ ã§å©ç¨ã§ããã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã¨ãç°¡åãªã¤ã³ã¿ã¼ããªã¿ãä½ãã®ã«ããããã©ããã£ã¦çµã¿åãããããç´¹ä»ãã¾ããã
ããã§ã¯ãç¾å¨å®è£ ããã¦ããã¢ãããã©ã³ã¹ãã©ã¼ãã¼ãå ¨ã¦ã¯ã«ãã¼ãã¦ãã¾ããã(ä¾ãã°ç¶ç¶ããªã¹ãã®ã¢ãããã©ã³ã¹ãã©ã¼ãã¼) ãã£ã¨æ å ±ãå¾ãããã«ãHaskellã®ã¦ã§ããµã¤ãã«ããã©ã¤ãã©ãªã®ããã¥ã¡ã³ããèªããã¨ããããããã¾ãã
ã¢ãããã©ã³ã¹ãã©ã¼ãã¼ã使ããã¨ã§ãä»ã®ã¢ããªã±ã¼ã·ã§ã³ã§ãããããã¨ããä¸æ岩ã§ãæ製ã®ã¢ããã«ã¾ã¨ãä¸ããæ§ã ãªã¢ããªã±ã¼ã·ã§ã³ã«ç¹åããã¢ããããã¨ãç°¡åã«ä½ãåºããã¨ãã§ãã¾ãã
Happy hacking in Haskell!!
References
- [1] GHC Developers. Glasgow Haskell Compiler Homepage. Available from: http://www. haskell.org/ghc, 2008. Last visited: 2008-10-07.
- [2] Mark P. Jones. Functional programming with overloading and higher-order polymorphism. In First International Spring School on Advanced Functional Programming Techniques, vol- ume 925 of Lecture Notes in Computer Science, pages 97â136, B Ìastad, Sweden, May 1995. Springer-Verlag.