
Model-Updater-Viewã¯ãäž»ã«ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ãéçºããããã«
Elmèšèªã§äœ¿çšãããŠããæ©èœçãªãã¿ãŒã³ã§ãã ããã䜿çšããã«ã¯ãããã°ã©ã ã®å®å
šãªç¶æ
ã衚ãã¢ãã«ã¿ã€ããããã°ã©ã ãåå¿ããç°å¢ã€ãã³ããèšè¿°ããã¡ãã»ãŒãžã¿ã€ããç¶æ
ã®å€æŽãå€ãç¶æ
ãšã¡ãã»ãŒãžããããã°ã©ã ã®æ°ããç¶æ
ãäœæããã¢ããããŒã¿é¢æ°ãããã³ãã¥ãŒé¢æ°ãäœæããå¿
èŠããããŸããããã°ã©ã ã®ç¶æ
ã«å¿ããŠãã¡ãã»ãŒãžã¿ã€ãã®ã€ãã³ããçºçãããå¿
èŠãªç°å¢åœ±é¿ãèšç®ããŸãã ãã®ãã¿ãŒã³ã¯éåžžã«äŸ¿å©ã§ãããå°ããªæ¬ ç¹ããããŸããç¹å®ã®ããã°ã©ã ã®ç¶æ
ã«ãšã£ãŠæå³ã®ããã€ãã³ããèšè¿°ããããšã¯ã§ããŸããã
State OOãã¿ãŒã³ã䜿çšãããšãåæ§ã®åé¡ãçºçããŸãïŒ
解決ãããŸã ïŒã
Elmèšèªã¯ã·ã³ãã«ã§ããéåžžã«å³å¯ã§ã-ã¢ããããŒã¿æ©èœãå°ãªããšãäœããã®åœ¢ã§ã¢ãã«ç¶æ
ãšã¡ãã»ãŒãžã€ãã³ãã®ãã¹ãŠã®å¯èœãªçµã¿åãããåŠçããããšããã§ãã¯ããŸãã ãã®ãããéåžžã¯ã¢ãã«ã倿Žããã«ããããã«ãäºçްã§ã¯ãããŸãã远å ã®ã³ãŒããèšè¿°ããå¿
èŠããããŸãã IdrisãScalaãC ++ãHaskellãªã©ãããè€éãªèšèªã§ãããåé¿ããæ¹æ³ã瀺ããããšæããŸãã
ããã«ãããã¹ãŠã®ã³ãŒãã¯ãå®éšã®ããã«
GitHubã§å
¥æã§ããŸãã æãè峿·±ãå Žæãæ€èšããŠãã ããã
ã€ããªã¹
Idrisã¯ãäŸååããµããŒãããèšèªã§ãã ã€ãŸãã1ã€ã®å€æ°ã®åã¯å¥ã®å€æ°ã®å€ã«äŸåããå¯èœæ§ããããŸããããã®äžã§ã³ã³ãã€ã©ã¯åä»ããç£èŠã§ããŸãã ã€ããªã¹ã®
åã¯ãHaskellã®
äžè¬åããã代æ°åã«äŒŒãŠããŸãã ããã¯ãåãã©ã¡ãŒã¿ãŒã®ãªã¹ããšäžé£ã®ã³ã³ã¹ãã©ã¯ã¿ãŒïŒãã®åã®ãªããžã§ã¯ããäœæãã颿°ïŒã«ãã£ãŠèšè¿°ãããŸãã Haskellãšã¯ç°ãªããåãã©ã¡ãŒã¿ãŒã¯ä»ã®åãåã¯ã©ã¹ã ãã§ãªãã颿°ãªã©ã®å€ã§ããããŸãã
Model-Updater-Viewãã¿ãŒã³ã䜿çšããåçŽãªã¢ããªã±ãŒã·ã§ã³ã®ã¿ã€ãã«ã€ããŠèª¬æããŸãããã
data Application : (model:Type) -> (msg: model -> Type) -> (vtype : Type -> Type) -> Type where MUV : model -> (updater : (m:model) -> (msg m) -> model) -> (view : (m:model) -> vtype (msg m)) -> Application model msg vtype
ããã§ã¯ããã©ã¡ãŒã¿åãããã¢ããªã±ãŒã·ã§ã³ããŒã¿ã¿ã€ãã«ã€ããŠèª¬æããŸãã ãã®ãã©ã¡ãŒã¿ãŒã¯
ãã¢ãã«
ã¿ã€ã ãã¢ãã«
ã¿ã€ãã®
å€ãããã°ã©ã ã®ç¹å®ã®ç¶æ
ã§çºçããå¯èœæ§ã®ããã€ãã³ãã¿ã€ãã«å€æããmsg颿°ãããã³ã€ãã³ãã¿ã€ãã«ãã£ãŠãã©ã¡ãŒã¿ãŒåããããã¥ãŒã¿ã€ãã§ãããã©ã¡ãŒã¿ãŒã¿ã€ãããåçŽã¿ã€ããžã®é¢æ°ãšããŠè§£éã§ããŸãã
é«çš®é¡ã®ã¿ã€ãã«é¢ããåæ
çãªäœè«ããã¯ãåãã©ã¡ãŒã¿ãŒã䜿çšãããå¯äžã®å Žæã§ãããããèªäœã«åãã©ã¡ãŒã¿ãŒããããŸãã ãã®æ©èœã¯ãã¹ãŠã®èšèªã§æäŸãããŠããããã§ã¯ãããŸãã-Elmãå«ããå©çšã§ããŸããã ãã ãããã®äŸã§ã¯ããã¥ãŒã¯ã¢ããªã±ãŒã·ã§ã³ã¿ã€ããã©ã¡ãŒã¿ã«é
眮ããããããçŸããã®ãããã«-ãã¿ãŒã³ã®ã³ã³ããŒãã³ãã§ããããšã瀺ããŠããŸãã Elmã®ããã«æ¯ãèãããšãã§ããŸã-åºå®ã®ãã©ã¡ãŒã¿ãŒåãããåãViewãšããŠäœ¿çšããŸãïŒElmã§ã¯Html msgã§ãïŒã
HKTã¯äŸååã䜿çšããããã«å¿
èŠã§ã¯ãªãããšã«æ³šæããŠãã ãã-ãããã¯
ã©ã ããã¥ãŒãã®ç°ãªããšããžã§ã
msg颿°ã¯ç°åžžã§ã-å€ã§ã¯ãªãåãè¿ããŸãã å®è¡æã«ã¯ãå€ã®ã¿ã€ãã«ã€ããŠã¯äœãããããŸãã-ã³ã³ãã€ã©
ã¯äžèŠãªæ
å ±
ããã¹ãŠ
æ¶å»ããŸãã ã€ãŸãããã®ãããªé¢æ°ã¯ã³ã³ãã€ã«æ®µéã§ã®ã¿åŒã³åºãããšãã§ããŸãã
MUVã¯ã³ã³ã¹ãã©ã¯ã¿ãŒã§ãã ãã©ã¡ãŒã¿ãŒãåããŸãïŒmodel-ããã°ã©ã ã®åæç¶æ
ãupdater-å€éšã€ãã³ãã§ç¶æ
ãæŽæ°ããæ©èœãview-å€éšãã¥ãŒãäœæããæ©èœã ã¢ããããŒã¿ããã³ãã¥ãŒé¢æ°ã®ã¿ã€ãã¯ã¢ãã«å€ã«äŸåããããšã«æ³šæããŠãã ããïŒã¿ã€ããã©ã¡ãŒã¿ãŒããmsg颿°ã䜿çšïŒã
ãã®ã¢ããªã±ãŒã·ã§ã³ãå®è¡ããæ¹æ³ãèŠãŠã¿ãŸããã
muvRun : (Application modelType msgType IO) -> IO a muvRun (MUV model updater view) = do msg <- view model muvRun (MUV (updater model msg) updater view)
å€éšãã¥ãŒãšããŠãå
¥å/åºåæäœãéžæããŸããïŒã€ããªã¹ã§ã¯ãHaskellã®ããã«ãå
¥å/åºåæäœã¯ãã¡ãŒã¹ãã¯ã©ã¹ã®å€ã§ãããããå®è¡ããã«ã¯è¿œå ã®æé ãå®è¡ããå¿
èŠããããéåžžã¯ãã®ãããªæäœãã¡ã€ã³é¢æ°ããè¿ããŸãïŒã
IOã«ã€ããŠç°¡åã«èª¬æããŸãã¿ã€ãïŒIO aïŒã®æäœãå®è¡ãããšã空ã®å¯èœæ§ãããå€éšã®äžçã«äœããã®åœ±é¿ããããã¿ã€ãaã®å€ãããã°ã©ã ã«è¿ãããŸãããæšæºã©ã€ãã©ãªã®é¢æ°ã¯ãã¿ã€ãIO bã®æ°ããå€ãçæããããšã«ãã£ãŠã®ã¿åŠçã§ããããã«èšèšãããŠããŸãã ãããã£ãŠãçŽç²ãªé¢æ°ã¯å¯äœçšã®ãã颿°ããåé¢ãããŸãã ããã¯å€ãã®ããã°ã©ããŒã«ãšã£ãŠçããããšã§ãããããä¿¡é Œæ§ã®é«ãã³ãŒããæžãã®ã«åœ¹ç«ã¡ãŸãã
muvRun颿°ã¯å
¥å/åºåãçæãããããIOãè¿ãå¿
èŠããããŸãããå®äºããããšã¯ãªããããæäœã®ã¿ã€ãã¯ä»»æã§ã-IO
次ã«ã䜿çšãããšã³ãã£ãã£ã®ã¿ã€ãã«ã€ããŠèª¬æããŸãã
data Model = Logouted | Logined String data MsgOuted = Login String data MsgIned = Logout | Greet total msgType : Model -> Type msgType Logouted = MsgOuted msgType (Logined _) = MsgIned
ããã§ã¯ã2ã€ã®ã€ã³ã¿ãŒãã§ã€ã¹ç¶æ
ãååšããããšãåæ ããŠãã¢ãã«ã¿ã€ãã«ã€ããŠèª¬æããŸãããŠãŒã¶ãŒã¯ãã°ã€ã³ããŠããããStringåã®ååãæã€ãŠãŒã¶ãŒããã°ã€ã³ããŠããŸãã
次ã«ãã¢ãã«ã®ããŸããŸãªããŒãžã§ã³ã«é¢é£ãã
2çš®é¡ã®ã¡ãã»ãŒãžã«ã€ããŠèª¬æããŸãããã°ã€ã³ããŠããå Žåã¯ç¹å®ã®ååã§ã®ã¿ãã°ã€ã³ã§ãããã°ã€ã³ããŠããå Žåã¯ãã°ã¢ãŠããããæšæ¶ããããšãã§ããŸãã Idrisã¯åŒ·ãåä»ããããèšèªã§ãããç°ãªãåãæ··åããå¯èœæ§ã¯ãããŸããã
ãããŠæåŸã«ãã¡ãã»ãŒãžã¿ã€ãã«äžèŽããããã«ã¢ãã«å€ãèšå®ãã颿°ã
颿°ã¯totalãšããŠå®£èšãããŸã-ã€ãŸããèœäžãŸãã¯ããªãŒãºããŠã¯ãªããŸãããã³ã³ãã€ã©ãŒã¯ããããã¬ãŒã¹ããããšããŸãã msgTypeã¯ã³ã³ãã€ã«æ®µéã§åŒã³åºãããŸããã€ãŸãããã®é¢æ°ã®å®è¡ãã·ã¹ãã ãªãœãŒã¹ã®æ¯æžã«ã€ãªããããšãä¿èšŒããããšã¯ã§ããŸããããå
šäœãšããŠã¯ããšã©ãŒã®ããã«ã³ã³ãã€ã«ããã³ã°ããªãããšãæå³ããŸãã
ãŸãã眲åã«IOããªãããããrm -rf /ããå®è¡ããªãããšãä¿èšŒãããŠããŸãã
ã¢ããããŒã¿ãŒã«ã€ããŠèª¬æããŸãã
total updater : (m:Model) -> (msgType m) -> Model updater Logouted (Login name) = Logined name updater (Logined name) Logout = Logouted updater (Logined name) Greet = Logined name
ãã®é¢æ°ã®ããžãã¯ã¯æç¢ºã ãšæããŸãã ããäžåºŠå
šäœã«æ³šæããã-ããã¯ãã€ããªã¹ã³ã³ãã€ã©ããåã·ã¹ãã ã§èš±å¯ãããŠãããã¹ãŠã®ä»£æ¿æ¡ãæ€èšããããšãæ€èšŒããããšãæå³ããã Elmããã®ãããªãã§ãã¯ãå®è¡ããŸããããŸã ãã°ã€ã³ããŠããªãå Žåã¯ãã°ã¢ãŠãã§ããªãããšãç¥ãããæ¡ä»¶ã®æç€ºçãªåŠçãå¿
èŠã«ãªããŸã
updater Logouted Logout = ???
Idrisã¯ã远å ã®ãã§ãã¯ã§åã®äžäžèŽãæ€åºããŸãã
次ã«ããã¥ãŒãéå§ããŸããããéåžžã®UIã§ã¯ããããã³ãŒãã®æãé£ããéšåã«ãªããŸãã
total loginPage : IO MsgOuted loginPage = do putStr "Login: " map Login getLine total genMsg : String -> MsgIned genMsg "" = Logout genMsg _ = Greet total workPage : String -> IO MsgIned workPage name = do putStr ("Hello, " ++ name ++ "\n") putStr "Input empty string for logout or nonempty for greeting\n" map genMsg getLine total view : (m: Model) -> IO (msgType m) view Logouted = loginPage view (Logined name) = workPage name
ãã¥ãŒã¯ãåãã¢ãã«å€ã«åã³äŸåããã¡ãã»ãŒãžãè¿ãI / Oæäœãäœæããå¿
èŠããããŸãã æ¬¡ã®2ã€ã®ãªãã·ã§ã³ããããŸãããLoginïŒããšããã¡ãã»ãŒãžã衚瀺ããloginPageã¯ãããŒããŒãããè¡ãèªã¿åãããã°ã€ã³ã¡ãã»ãŒãžã§å²ã¿ããã©ã¡ãŒã¿usernameã§workPageã衚瀺ããæšæ¶ã衚瀺ããŠç°ãªãã¡ãã»ãŒãžãè¿ããŸãïŒãã ããåãã¿ã€ã-MsgInedïŒãŠãŒã¶ãŒã¯ç©ºãŸãã¯ç©ºã§ãªãæååãå
¥åããŸãã ãã¥ãŒã¯ãã¢ãã«å€ã«å¿ããŠãããã®æäœã®1ã€ãè¿ããã³ã³ãã€ã©ã¯ããããç°ãªããšããäºå®ã«ãããããããåããã§ãã¯ããŸãã
ããã§ãã¢ããªã±ãŒã·ã§ã³ãäœæããŠå®è¡ã§ããŸã
app : Application Model Main.msgType IO app = MUV Logouted updater view main : IO () main = muvRun app
ããã§åŸ®åŠãªç¹ã«æ³šæããå¿
èŠããããŸã-muvRun颿°ã¯ãaãæå®ãããŠããªã
IO aãè¿ããã¡ã€ã³å€ã¯
IOïŒïŒåã§ããããã§
ïŒïŒã¯ãéåžž
UnitãšåŒã°ããåäžã®å€ãæã€åã®ååã§ãã
ïŒïŒ ã ããããã³ã³ãã€ã©ã¯ãããç°¡åã«è¡ããŸãã 代ããã«ïŒïŒã代å
¥ããŸãã
Scalaããã³ãã¹äŸåå
Scalaã¯äŸååãå®å
šã«ã¯ãµããŒãããŠããŸããããåç
§ããããªããžã§ã¯ãã®ã€ã³ã¹ã¿ã³ã¹ã«äŸåããåããããŸãïŒãã¹äŸååïŒã äŸååã®çè«ã§ã¯ããããã¯ã·ã°ãåã®å€åœ¢ãšããŠèª¬æã§ããŸãã ãã¹äŸååã䜿çšãããšãç°ãªããã¯ãã«ç©ºéããã®ãã¯ãã«ã®æãããã¿ãçŠæ¢ããã
ã誰ãšèª°ã«ãã¹ã§ããããèšè¿°
ã§ããŸã ã ããããããåçŽãªã¿ã¹ã¯ã«ã¯ããããé©çšããŸãã
sealed abstract class MsgLogouted case class Login(name: String) extends MsgLogouted sealed abstract class MsgLogined case class Logout() extends MsgLogined case class Greet() extends MsgLogined abstract class View[Msg] { def run() : Msg } sealed abstract class Model { type Message def view() : View[Message] } case class Logouted() extends Model { type Message = MsgLogouted override def view() : View[Message] .... } case class Logined(name: String) extends Model { type Message = MsgLogined override def view() : View[Message] .... }
Scalaã®ä»£æ°åã¯ãç¶æ¿ã«ãã£ãŠã¢ãã«åãããŸãã åã¯ç¹å®ã®
ã·ãŒã«ããããæœè±¡ã¯ã©ã¹ã«å¯Ÿå¿ããåã³ã³ã¹ãã©ã¯ã¿ãŒã¯ãããã
ã±ãŒã¹ã¯ã©ã¹ãç¶æ¿ããŸãã ãããã代æ°åãšããŠæ£ç¢ºã«äœ¿çšãããã¹ãŠã®å€æ°ã芪ã®
ã·ãŒã«ãããæœè±¡ã¯ã©ã¹ã«å±ãããã®ãšããŠèšè¿°ããããšããŸãã
ããã°ã©ã å
ã®ã¯ã©ã¹MsgLoginedããã³MsgLogoutedã«ã¯å
±éã®ç¥å
ããããŸããã ç¹å®ã®ã¿ã€ãã®ã¡ãã»ãŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ããã¥ãŒé¢æ°ãã¢ãã«ã®ããŸããŸãªã¯ã©ã¹ã«åæ£ãããå¿
èŠããããŸããã ããã«ã¯ãOOã®æ¯æè
ãé«ãè©äŸ¡ããå©ç¹ããããŸããã³ãŒãã¯ããžãã¹ããžãã¯ã«åŸã£ãŠã°ã«ãŒãåããã1ã€ã®ãŠãŒã¹ã±ãŒã¹ã«é¢é£ãããã®ã¯ãã¹ãŠè¿ãã«ããããšãããããŸãã ãããããã¥ãŒãå¥ã®æ©èœã«åå²ãããã®æ©èœãå¥ã®äººã«ç§»ããããšæããŸãã
次ã«ãã¢ããããŒã¿ãŒãå®è£
ããŸã
object Updater { def update(model: Model)(msg: model.Message) : Model = { model match { case Logouted() => msg match { case Login(name) => Logined(name) } case Logined(name) => msg match { case Logout() => Logouted() case Greet() => model } } } }
ããã§ã¯ããã¹äŸååã䜿çšããŠãæåã®å€ãã2çªç®ã®åŒæ°ã®åã説æããŸãã Scalaããã®ãããªäŸåé¢ä¿ãèªèããããã«ã¯ã颿°ãã«ãªãŒåããã圢åŒã§ãã€ãŸãã2çªç®ã®åŒæ°ã®é¢æ°ãè¿ãæåã®åŒæ°ã®é¢æ°ãšããŠèšè¿°ããå¿
èŠããããŸãã æ®å¿µãªãããScalaã¯ãã®æç¹ã§å€ãã®åãã§ãã¯ãå®è¡ããŸããããã®ãããã³ã³ãã€ã©ãŒã¯ååãªæ
å ±ãæã£ãŠããŸãã
次ã«ãã¢ãã«ãšãã¥ãŒã®å®å
šãªå®è£
ã瀺ããŸã
case class Logouted() extends Model { type Message = MsgLogouted override def view() : View[Message] = new View[Message] { override def run() = { println("Enter name ") val name = scala.io.StdIn.readLine() Login(name) } } } case class Logined(name: String) extends Model { type Message = MsgLogined override def view() : View[Message] = new View[Message] { override def run() = { println(s"Hello, $name") println("Empty string for logout, nonempy for greeting.") scala.io.StdIn.readLine() match { case "" => Logout() case _ => Greet() } } } } abstract class View[Msg] { def run() : Msg } object Viewer { def view(model: Model): View[model.Message] = { model.view() } }
ãã¥ãŒé¢æ°ã«ãã£ãŠè¿ãããåã¯ãåŒæ°ã®ã€ã³ã¹ã¿ã³ã¹ã«ãã£ãŠç°ãªããŸãã ããããå®è£
ã®ããã«ã圌女ã¯ã¢ãã«ã«ç®ãåããŸãã
ãã®ããã«äœæãããã¢ããªã±ãŒã·ã§ã³ã¯ããã®ããã«èµ·åããŸã
object Main { import scala.annotation.tailrec @tailrec def process(m: Model) { val msg = Viewer.view(m).run() process(Updater.update(m)(msg)) } def main(args: Array[String]) = { process(Logouted()) } }
ãããã£ãŠãã©ã³ã¿ã€ã ã·ã¹ãã ã®ã³ãŒãã¯ã¢ãã«ã®å
éšæ§é ãšã¡ãã»ãŒãžã®ã¿ã€ãã«ã€ããŠäœãç¥ããŸããããã³ã³ãã€ã©ãŒã¯ã¡ãã»ãŒãžãçŸåšã®ã¢ãã«ãšäžèŽããããšã確èªã§ããŸãã
ããã§ã¯ããã¹äŸååã«ãã£ãŠæäŸããããã¹ãŠã®æ©èœã¯å¿
èŠãããŸããã§ããã ããšãã°ããã«ããšãŒãžã§ã³ãã®äžçãã·ãã¥ã¬ãŒããããšããªã©ãModel-Updater-Viewã·ã¹ãã ã®è€æ°ã®ã€ã³ã¹ã¿ã³ã¹ãåæã«æäœãããšãè峿·±ãããããã£ã衚瀺ãããŸãïŒãã¥ãŒã¯ãäžçã«å¯ŸãããšãŒãžã§ã³ãã®å¹æã§ããããã£ãŒãããã¯ãåãåããŸãïŒã ãã®å Žåãã³ã³ãã€ã©ã¯ããã¹ãŠã®ãšãŒãžã§ã³ããåãã¿ã€ãã§ãããšããäºå®ã«ãããããããã¡ãã»ãŒãžãæå³ããããšãŒãžã§ã³ãã«ãã£ãŠåŠçãããŠããããšãæ€èšŒããŸããã
C ++
C ++ã¯ãå®çŸ©ããã¹ãŠ1ã€ã®ãã¡ã€ã«ã§äœæãããŠããå Žåã§ããå®çŸ©ã®é åºã«äŸç¶ãšããŠææã§ãã ããã«ãããäžäŸ¿ãçããŸãã ã¢ã€ãã¢ã瀺ãã®ã«äŸ¿å©ãªé åºã§ã³ãŒããæç€ºããŸãã ã³ã³ãã€ã«çšã«æ³šæãããããŒãžã§ã³ã¯
GitHubã§èŠãããšãã§ããŸãã
代æ°åã¯Scalaãšåãæ¹æ³ã§å®è£
ã§ããŸã-æœè±¡ã¯ã©ã¹ã¯åã«å¯Ÿå¿ããç¹å®ã®åå«ã¯ä»£æ°åã®ã³ã³ã¹ãã©ã¯ã¿ãŒïŒéåžžã®C ++ã³ã³ã¹ãã©ã¯ã¿ãŒãšæ··åããªãããã«ãã³ã³ã¹ãã©ã¯ã¿ãŒã¯ã©ã¹ããšåŒã³ãŸãããïŒã«å¯Ÿå¿ããŸãã
C ++ã¯ãã¹äŸååã
ãµããŒãããŠããŸãããã³ã³ãã€ã©ã¯ãé¢é£ä»ããããŠããå®éã®åãç¥ããªãéãããã®åãæœè±¡çã«äœ¿çšã§ããŸããã ãããã£ãŠãModel-Updater-Viewã䜿çšããŠå®è£
ããããšã¯ã§ããŸããã
ãã ããC ++ã«ã¯åŒ·åãªãã³ãã¬ãŒãã·ã¹ãã ããããŸãã åã®ã¢ãã«å€ãžã®äŸåã¯ããšã°ãŒã¯ãã£ãã·ã¹ãã ã®å°çšããŒãžã§ã³ã®ãã³ãã¬ãŒããã©ã¡ãŒã¿ãŒã§é衚瀺ã«ã§ããŸãã
struct Processor { virtual const Processor *next() const = 0; }; template <typename CurModel> struct ProcessorImpl : public Processor { const CurModel * model; ProcessorImpl<CurModel>(const CurModel* m) : model(m) { }; const Processor *next() const { const View<typename CurModel::Message> * view = model->view(); const typename CurModel::Message * msg = view->run(); delete view; const Model * newModel = msg->process(model); delete msg; return newModel->processor(); } };
å¿
èŠãªãã¹ãŠãéæããæ¬¡ã®å埩ã«é©ããæ°ããå®è¡ã·ã¹ãã ãè¿ããšããå¯äžã®æ¹æ³ãåããæœè±¡å®è¡ã·ã¹ãã ã«ã€ããŠèª¬æããŸãã å
·è±¡ããŒãžã§ã³ã«ã¯ãã³ãã¬ãŒããã©ã¡ãŒã¿ãŒããããåã¢ãã«ã³ã³ã¹ãã©ã¯ã¿ãŒã¯ã©ã¹ã«ç¹åãããŸãã ããã§éèŠãªã®ã¯ãç¹å®ã®åãã©ã¡ãŒã¿ãŒã䜿çšãããã³ãã¬ãŒãã®ç¹æ®åäžã«CurModelåã®ãã¹ãŠã®ããããã£ããã§ãã¯ãããããšã§ããããã³ãã¬ãŒãèªäœã®ã³ã³ãã€ã«æã«ã¯ããããèšè¿°ããå¿
èŠã¯ãããŸããïŒãã ãã
åã¯ã©ã¹ãå®è£
ããããã® æŠå¿µãŸãã¯
ä»ã®æ¹æ³ã䜿çš
ããããšã¯å¯èœã§ãïŒã Scalaã«ã¯ãã©ã¡ãŒã¿ãŒåãããåã®ããªã匷åãªã·ã¹ãã ããããŸããããã©ã¡ãŒã¿ãŒåãããåã®ã³ã³ãã€ã«æã«ããããã£åã®ãã©ã¡ãŒã¿ãŒåãã§ãã¯ãå®è¡ããŸãã ãã®ãããªãã¿ãŒã³ã®å®è£
ã¯å°é£ã§ãããåã¯ã©ã¹ã®ãµããŒãã®ãããã§å¯èœã§ãã
ã¢ãã«ã«ã€ããŠèª¬æããŸãã
struct Model { virtual ~Model() {}; virtual const Processor *processor() const = 0; }; struct Logined : public Model { struct Message { const virtual Model * process(const Logined * m) const = 0; virtual ~Message() {}; }; struct Logout : public Message { const Model * process(const Logined * m) const; }; struct Greet : public Message { const Model * process(const Logined * m) const; }; const std::string name; Logined(std::string lname) : name(lname) { }; struct LoginedView : public View<Message> { ... }; const View<Message> * view() const { return new LoginedView(name); }; const Processor *processor() const { return new ProcessorImpl<Logined>(this); }; }; struct Logouted : public Model { struct Message { const virtual Model * process(const Logouted * m) const = 0; virtual ~Message() {}; }; struct Login : public Message { const std::string name; Login(std::string lname) : name(lname) { }; const Model * process(const Logouted * m) const; }; struct LogoutedView : public View<Message> { ... }; const View<Message> * view() const { return new LogoutedView(); }; const Processor *processor() const { return new ProcessorImpl<Logouted>(this); }; };
ããã¹ãŠç¬èªã®ãã¢ãã«ã®ããã¶ã€ããŒã¯ã©ã¹ã-ã€ãŸãããããã¯ããããã«ç¹åããã¡ãã»ãŒãžã¯ã©ã¹ãšãã¥ãŒã¯ã©ã¹ãå«ã¿ããŸãèªåèªèº«ã®ããã®å®è¡ã·ã¹ãã ãäœæããæ¹æ³ãç¥ã£ãŠããŸãã ãã€ãã£ãã¿ã€ãã®ãã¥ãŒã«ã¯ããã¹ãŠã®ã¢ãã«ã«å
±éã®ç¥å
ããããããè€éãªå®è¡ã·ã¹ãã ãéçºããå Žåã«åœ¹ç«ã¡ãŸãã ã¡ãã»ãŒãžã¿ã€ãã¯å®å
šã«åé¢ãããå
±éã®ç¥å
ãæããªãããšãéèŠã§ãã
ã¢ããããŒã¿ãŒã®å®è£
ã¯ãã¢ãã«ã®ã¿ã€ããå®å
šã«èšè¿°ããå¿
èŠããããããã¢ãã«ãšã¯å¥ã§ãã
const Model * Logouted::Login::process(const Logouted * m) const { delete m; return new Logined(name); }; const Model * Logined::Logout::process(const Logined * m) const { delete m; return new Logouted(); }; const Model * Logined::Greet::process(const Logined * m) const { return m; };
次ã«ãã¢ãã«ã®å
éšãšã³ãã£ãã£ãå«ãããã¥ãŒã«é¢é£ãããã¹ãŠã®ãã®ããŸãšããŸããã
template <typename Message> struct View { virtual const Message * run() const = 0; virtual ~View<Message>() {}; }; struct Logined : public Model { struct LoginedView : public View<Message> { const std::string name; LoginedView(std::string lname) : name(lname) {}; virtual const Message * run() const { char buf[16]; printf("Hello %s", name.c_str()); fgets(buf, 15, stdin); return (*buf == 0 || *buf == '\n' || *buf == '\r') ? static_cast<const Message*>(new Logout()) : static_cast<const Message *>(new Greet); }; }; const View<Message> * view() const { return new LoginedView(name); }; }; struct Logouted : public Model { struct LogoutedView : public View<Message> { virtual const Message * run() const { char buf[16]; printf("Login: "); fgets(buf, 15, stdin); return new Login(buf); }; }; const View<Message> * view() const { return new LogoutedView(); }; };
ãããŠæåŸã«ãã¡ã€ã³ãæžããŸã
int main(int argc, char ** argv) { const Processor * p = new ProcessorImpl<Logouted>(new Logouted()); while(true) { const Processor * pnew = p->next(); delete p; p = pnew; } return 0; }
ãããŠåã³ãScalaããã§ã«åã¯ã©ã¹ããããŸã
æ§é äžããã®å®è£
ã¯ã»ãŒå®å
šã«C ++ããŒãžã§ã³ãç¹°ãè¿ããŸãã
åæ§ã®ã³ãŒã abstract class View[Message] { def run(): Message } abstract class Processor { def next(): Processor; } sealed abstract class Model { def processor(): Processor } sealed abstract class LoginedMessage case class Logout() extends LoginedMessage case class Greet() extends LoginedMessage case class Logined(val name: String) extends Model { override def processor(): Processor = new ProcessorImpl[Logined, LoginedMessage](this) } sealed abstract class LogoutedMessage case class Login(name: String) extends LogoutedMessage case class Logouted() extends Model { override def processor(): Processor = new ProcessorImpl[Logouted, LogoutedMessage](this) } object Main { import scala.annotation.tailrec @tailrec def process(p: Processor) { process(p.next()) } def main(args: Array[String]) = { process(new ProcessorImpl[Logouted, LogoutedMessage](Logouted())) } }
ããããå®è¡ç°å¢ã®å®è£
ã§ã¯ã埮åŠãªåé¡ãçºçããŸãã
class ProcessorImpl[M <: Model, Message](model: M)( implicit updater: (M, Message) => Model, view: M => View[Message] ) extends Processor { def next(): Processor = { val v = view(model) val msg = v.run() val newModel = updater(model,msg) newModel.processor() } }
ããã«ãæ°ããç¥ç§çãªãã©ã¡ãŒã¿ãŒã衚瀺ãããŸã
ïŒæé»ã®ã¢ããããŒã¿ãŒïŒïŒMãMessageïŒ=> ModelãviewïŒM => View [Message]ïŒ ã implicitããŒã¯ãŒãã¯ã颿°ïŒããæ£ç¢ºã«ã¯ã¯ã©ã¹ã³ã³ã¹ãã©ã¯ã¿ãŒïŒãåŒã³åºããããšãã³ã³ãã€ã©ãŒãã³ã³ããã¹ãã§æé»çãšããŒã¯ãããé©åãªã¿ã€ãã®ãªããžã§ã¯ããæ¢ããããããé©åãªãã©ã¡ãŒã¿ãŒãšããŠæž¡ãããšãæå³ããŸãã ããã¯ããªãè€éãªæŠå¿µã§ããããã®ã¢ããªã±ãŒã·ã§ã³ã®1ã€ã¯åã¯ã©ã¹ã®å®è£
ã§ãã ããã§ã¯ãã¢ãã«ãšã¡ãã»ãŒãžã®ç¹å®ã®å®è£
ã«å¿
èŠãªãã¹ãŠã®æ©èœãæäŸããããšãã³ã³ãã€ã©ã«çŽæããŸãã ä»ããã®çŽæãå®ã£ãŠãã ããã
object updaters { implicit def logoutedUpdater(model: Logouted, msg: LogoutedMessage): Model = { (model, msg) match { case (Logouted(), Login(name)) => Logined(name) } } implicit def viewLogouted(model: Logouted) = new View[LogoutedMessage] { override def run() : LogoutedMessage = { println("Enter name ") val name = scala.io.StdIn.readLine() Login(name) } } implicit def loginedUpdater(model: Logined, msg: LoginedMessage): Model = { (model, msg) match { case (Logined(name), Logout()) => Logouted() case (Logined(name), Greet()) => model } } implicit def viewLogined(model: Logined) = new View[LoginedMessage] { val name = model.name override def run() : LoginedMessage = { println(s"Hello, $name") println("Empty string for logout, nonempy for greeting.") scala.io.StdIn.readLine() match { case "" => Logout() case _ => Greet() } } } } import updaters._
ãã¹ã±ã«
äž»æµã®Haskellã«ã¯äŸååã¯ãããŸããã ãŸããScalaããã³C ++ã§ãã¿ãŒã³ãå®è£
ãããšãã«åºæ¬çã«äœ¿çšããç¶æ¿ããããŸããã ãã ããïŒäŸååã®èŠçŽ ãæã€ïŒåäžã¬ãã«ã®ç¶æ¿ã¯ãå€ããå°ãªããæšæºã®èšèªæ¡åŒµæ©èœã§ããTypeFamiliesãšExistentialQuantificationã䜿çšããŠã¢ãã«åã§ããŸãã åOOPã¯ã©ã¹ã®äžè¬çãªã€ã³ã¿ãŒãã§ã€ã¹ã®å ŽåãäŸåããããã¡ããªãåãååšããåã¯ã©ã¹ãäœæãããåã¯ã©ã¹èªäœã¯å¥ã®åãšããŠè¡šãããåäžã®ã³ã³ã¹ãã©ã¯ã¿ã§ãååšãããåã«ã©ãããããŸãã
data Model = forall m. (Updatable m, Viewable m) => Model m class Updatable m where data Message m :: * update :: m -> (Message m) -> Model class (Updatable m) => Viewable m where view :: m -> (View (Message m)) data Logouted = Logouted data Logined = Logined String
ã¢ããããŒã¿ãšãã¥ãŒãå¯èœãªéãåºããããšããããã2ã€ã®ç°ãªãã¿ã€ãã®ã¯ã©ã¹ãäœæããŸããããä»ã®ãšããããŸããããŸããã§ããã
ã¢ããããŒã¿ãŒã®å®è£
ã¯ç°¡åã§ã
instance Updatable Logouted where data Message Logouted = Login String update Logouted (Login name) = Model (Logined name) instance Updatable Logined where data Message Logined = Logout | Greeting update m Logout = Model Logouted update m Greeting = Model m
IOããã¥ãŒãšããŠä¿®æ£ããå¿
èŠããããŸããã æœè±¡åãéåžžã«è€éã«ããã³ãŒãã®äžè²«æ§ãé«ããããšãã詊ã¿-ã¢ãã«ã¿ã€ãã¯ã䜿çšãããã¥ãŒãç¥ãå¿
èŠããããŸãã
import System.IO type View a = IO a instance Viewable Logouted where view Logouted = do putStr "Login: " hFlush stdout fmap Login getLine instance Viewable Logined where view (Logined name) = do putStr $ "Hello " ++ name ++ "!\n" hFlush stdout l <- getLine pure $ if l == "" then Logout else Greeting
ãŸããã©ã³ã¿ã€ã ã¯ã€ããªã¹ã§åããšã»ãšãã©ç°ãªããŸãã
runMUV :: Model -> IO a runMUV (Model m) = do msg <- view m runMUV $ update m msg main :: IO () main = runMUV (Model Logouted)