-- A simple desk calculator showing the combination of GUIs with -- local state where the state is stored in an object. -- Therefore, the GUI runs as a constraint. import Tk import Ports import Char data CalcMsg = Button Char | Display String -- state contains value of current operand and an accumulator function: calcMgr :: (Int,Int->Int) -> [CalcMsg] -> Success calcMgr (d,f) (Display s : ms) = s=:=(show d) &> calcMgr (d,f) ms calcMgr (d,f) (Button b : ms) | isDigit b = calcMgr (10*d + ord b - ord '0', f) ms | b=='+' = calcMgr (0,((f d) + )) ms | b=='-' = calcMgr (0,((f d) - )) ms | b=='*' = calcMgr (0,((f d) * )) ms | b=='/' = calcMgr (0,((f d) `div` )) ms | b=='=' = calcMgr (f d, id) ms | b=='C' = calcMgr (0, id) ms -- the GUI needs a reference to the calculator object: parameter "calculator" calc_GUI calculator = TkCol [] [ TkEntry [TkRef display, TkText "0", TkBackground "yellow"], TkRow [] (map cbutton ['1','2','3','+']), TkRow [] (map cbutton ['4','5','6','-']), TkRow [] (map cbutton ['7','8','9','*']), TkRow [] (map cbutton ['C','0','=','/'])] where display free cbutton c = TkButton (button_pressed c) [TkText [c]] button_pressed c gp = let d free in send (Button c) calculator &> send (Display d) calculator &> tkCSetValue display d gp runCalcOnPort gp | let cm free in newObject calcMgr (0,id) cm & runWidgetOnPort (calc_GUI cm) gp = done main = openWish "Calculator" >>= runCalcOnPort