рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ, рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреА рдЕрдкрдиреА рд╡рд┐рд╢рд┐рд╖реНрдЯрддрд╛ рд╣реИ: рдЗрд╕рдореЗрдВ рд╣рдо рдбреЗрдЯрд╛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕реЗ рдмрджрд▓рддреЗ рдирд╣реАрдВред рд▓реЗрдХрд┐рди рдпрд╣ рдЕрдкрдиреА рд╕реАрдорд╛рдУрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд╕рд╛рде рд╕рдХреНрд░рд┐рдп рд░реВрдк рд╕реЗ рдмрд╛рддрдЪреАрдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдмрдирд╛рддреЗ рд╣реИрдВред рдПрдХ рдЕрдирд┐рд╡рд╛рд░реНрдп рднрд╛рд╖рд╛ рдореЗрдВ, рдЗрд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдХрд┐рд╕реА рднреА рдШрдЯрдирд╛ рдХрд╛ рдЬрд╡рд╛рдм "рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп" рдореЗрдВ рджреЗ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрдмрдХрд┐ рд╢реБрджреНрдз рдХрд╛рд░реНрдпрд╛рддреНрдордХ рднрд╛рд╖рд╛рдУрдВ рдореЗрдВ рд╣рдореЗрдВ рдмрд╣реБрдд рдЕрдВрдд рддрдХ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд╕рд╛рде рд╕рдВрдЪрд╛рд░ рд╕реНрдердЧрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдПрдХ рдирдпрд╛ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдкреНрд░рддрд┐рдорд╛рди рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рд╣рд╛рд▓ рд╣реА рдореЗрдВ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджрд┐рдпрд╛ рд╣реИ рдЬреЛ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рддрд╛ рд╣реИред рдФрд░ рдЙрд╕рдХрд╛ рдирд╛рдо
рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ (рдПрдлрдЖрд░рдкреА) рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓-рдХреЗрд▓реЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╣рд╛рд╕реНрдХреЗрд▓ рдореЗрдВ рдПрдХ рд╕рд╛рдВрдк рд▓рд┐рдЦрдХрд░ рдПрдлрдЖрд░рдкреА рдХреА рдореВрд▓ рдмрд╛рддреЗрдВ рджрд┐рдЦрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ред
рдЗрд╕ рдЖрд▓реЗрдЦ рдХреЗ рдмрд╛рдХреА рдиреЗ рдорд╛рди рд▓рд┐рдпрд╛ рдХрд┐ рдкрд╛рдардХ рдлрдВрдХреНрд╢рдирд▓рд░реНрд╕ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИред рдпрджрд┐ рдпрд╣ рдорд╛рдорд▓рд╛ рдирд╣реАрдВ рд╣реИ, рддреЛ рдореИрдВ рдЕрддреНрдпрдзрд┐рдХ рдЕрдиреБрд╢рдВрд╕рд╛ рдХрд░рддрд╛ рд╣реВрдВ рдХрд┐ рдЖрдк рдЕрдкрдиреЗ рдЖрдк рдХреЛ рдЙрдирдХреЗ рд╕рд╛рде рдкрд░рд┐рдЪрд┐рдд рдХрд░реЗрдВ, рдХреНрдпреЛрдВрдХрд┐ рдкреВрд░реЗ рд▓реЗрдЦ рдХреА рд╕рдордЭ рдЗрд╕ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддреА рд╣реИредрдореБрдЦреНрдп рд╡рд┐рдЪрд╛рд░
FRP рдореЗрдВ рджреЛ рдирдП рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░ рджрд┐рдЦрд╛рдИ рджреЗрддреЗ рд╣реИрдВ:
рдИрд╡реЗрдВрдЯ рдФрд░
рдмрд┐рд╣реЗрд╡рд┐рдпрд░ ред рдпреЗ рджреЛрдиреЛрдВ рдкреНрд░рдХрд╛рд░ рдХреЗ рдлрдВрдХреНрд╢рдирд▓рд░реНрд╕ рд╣реИрдВ, рдФрд░ рдЙрди рдкрд░ рдХрдИ рдХрд╛рд░реНрдп рдлрдВрдХреНрд╢рдВрд╕ рдХреЗ рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░реЛрдВ рджреНрд╡рд╛рд░рд╛ рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗред рд╣рдо рдЗрди рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВред
рдШрдЯрдирд╛
рдШрдЯрдирд╛ рдШрдЯрдирд╛рдУрдВ рдХреА рдПрдХ рдзрд╛рд░рд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдПрдХ рд╕рдЯреАрдХ рд╕рдордп рдЯрд┐рдХрдЯ рд╣реЛрддрд╛ рд╣реИред рдЗрд╕рдХреА рдХрд▓реНрдкрдирд╛ рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИ (рд╕рд┐рд░реНрдл рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕рдм рдХреБрдЫ рдЗрддрдирд╛ рд╕рд░рд▓ рдирд╣реАрдВ рд╣реИ):
type Event a = [(Time, a)]
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рдЗрд╡реЗрдВрдЯ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдПрдХ рдЪреИрдЯ рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдШрдЯрдирд╛рдУрдВ рдХреА рдПрдХ рдзрд╛рд░рд╛ рд╣реЛ рд╕рдХрддреА рд╣реИред
рдЬреИрд╕рд╛ рдХрд┐ рдкрд╣рд▓реЗ рд╣реА рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдШрдЯрдирд╛ рдлрдВрдХреНрд╢рдВрд╕ рдХреЗ рд╡рд░реНрдЧ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╣рдо рдЗрд╕рдХреЗ рд╕рд╛рде рдХреБрдЫ рдХреНрд░рд┐рдпрд╛рдПрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:
("Wellcome, " ++) <$> eusers
рдЙрди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рд╕реЗ рдЕрднрд┐рд╡рд╛рджрди рдХреА рдПрдХ рдзрд╛рд░рд╛ рдмрдирд╛рдПрдВрдЧреЗ, рдЬрд┐рдиреНрд╣реЛрдВрдиреЗ рдЪреИрдЯ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд┐рдпрд╛ рд╣реИред
рд╡реНрдпрд╡рд╣рд╛рд░
рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рдЕрд░реНрде рд╣реИ рдПрдХ рдореВрд▓реНрдп рдЬреЛ рд╕рдордп рдХреЗ рд╕рд╛рде рдмрджрд▓рддрд╛ рд╣реИред
type Behavior a = Time -> a
рдпрд╣ рдкреНрд░рдХрд╛рд░ рдЧреЗрдо рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рд▓рд┐рдП рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдЕрдиреБрдХреВрд▓ рд╣реИ, рд╣рдорд╛рд░реЗ рдЦреЗрд▓ рдореЗрдВ рд╕рд╛рдВрдк рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реЛрдЧрд╛ред
рд╣рдо рд▓рд╛рдЧреВ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рд╛рде рд╡реНрдпрд╡рд╣рд╛рд░ рдФрд░ рдШрдЯрдирд╛ рдХреЛ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ:
apply :: Behavior t (a -> b) -> Event ta -> Event tb apply bf ex = [(time, bf time x) | (time, x) <- ex]
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЗрд╕ рдкрд░рд┐рднрд╛рд╖рд╛ рд╕реЗ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рдЕрдВрджрд░ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ, рд╕рдордп рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдПред
рд╣рдо рд╕реАрдзреЗ рд╕рд╛рдВрдк рдХреЗ рдкрд╛рд╕ рдЬрд╛рддреЗ рд╣реИрдВред
рдЦреЗрд▓ рдпрд╛рдВрддреНрд░рд┐рдХреА
рдЕрднреА рдХреЗ рд▓рд┐рдП, рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреВрд▓ рдЬрд╛рдУ рдФрд░ рдЦреЗрд▓ рдХреЗ рдпрд╛рдВрддреНрд░рд┐рдХреА рдХреЛ рд▓реЗ рд▓реЛред рд╢реБрд░реБрдЖрдд рдХреЗ рд▓рд┐рдП, рдкреНрд░рдХрд╛рд░:
module Snake where type Segment = (Int, Int) type Pos = (Int, Int) type Snake = [Segment]
рд╕рд╛рдВрдк рдХрд╛ рдПрдХ рдЦрдВрдб рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХреА рдПрдХ рдЬреЛрдбрд╝реА рд╣реИ, рдФрд░ рд╕рд╛рдВрдк рд╣реА рдЗрди рдЦрдВрдбреЛрдВ рдХреА рдПрдХ рд╢реНрд░реГрдВрдЦрд▓рд╛ рд╣реИред рдЯрд╛рдЗрдк рдкреЛрдЬрд╝ рдХреЗрд╡рд▓ рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП рд╣реИред
startingSnake :: Snake startingSnake = [(10, 0), (11, 0), (12, 0)] wdth = 64 hdth = 48
рд╕рд╛рдБрдк рдХреА рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╕реНрдерд┐рддрд┐ рдФрд░ рдЦреЗрд▓ рдХреЗ рдореИрджрд╛рди рдХреЗ рдЖрдХрд╛рд░ рдХреЗ рд▓рд┐рдП рд╕реНрдерд┐рд░ рдмрдирд╛рдПрдВред
moveTo :: Pos -> Snake -> Snake moveTo hs = if h /= head s then h : init s else s keepMoving :: Snake -> Snake keepMoving s = let (x, y) = head s (x', y') = s !! 1 in moveTo (2*x - x', 2*y - y') s ifDied :: Snake -> Bool ifDied s@((x, y):_) = x<0 || x>=wdth || y<0 || y>=hdth || head s `elem` tail s
MoveTo рдлрд╝рдВрдХреНрд╢рди рд╕рд╛рдБрдк рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕реНрдерд╛рди рдкрд░ рд▓реЗ рдЬрд╛рддрд╛ рд╣реИ, KeepMoving рдЪрд▓рддрд╛ рд░рд╣рддрд╛ рд╣реИ, рдФрд░ ifDied рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╕рд╛рдБрдк рд╕реНрд╡рдпрдВ рдЦрд╛рдиреЗ рд╕реЗ рдорд░ рдЧрдпрд╛ рд╣реИ рдпрд╛ рд╕реАрдорд╛рдУрдВ рдХреЗ рд╕рд╛рде рдЯрдХрд░рд╛ рдЧрдпрд╛ рд╣реИред
рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдВ рдпрд╛рдВрддреНрд░рд┐рдХреА рд╕рдорд╛рдкреНрдд рд╣реЛрддреА рд╣реИ, рдЕрдм рд╕рдмрд╕реЗ рдХрдард┐рди рд╣рд┐рд╕реНрд╕рд╛ рдЖрдЧреЗ рд╣реИ - рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рддрд░реНрдХред
рддрд░реНрдХ
рд╣рдо рдЖрд╡рд╢реНрдпрдХ рдореЙрдбреНрдпреВрд▓ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдХреБрдЫ рд╕реНрдерд┐рд░рд╛рдВрдХ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВрдЧреЗ:
{-# LANGUAGE ScopedTypeVariables #-} import Control.Monad (when) import System.IO import System.Random import Graphics.UI.SDL as S hiding (flip) import Graphics.Rendering.OpenGL hiding (Rect, get) import Reactive.Banana as R import Data.Word (Word32) import Snake screenWidth = wdth*10 screenHeight = hdth*10 screenBpp = 32 ticks = 1000 `div` 20
рд╕реНрдХреНрд░реАрдирд╡рд┐рдж, рд╕реНрдХреНрд░реАрдирд╣рд╛рдЗрдЯ - рд╕реНрдХреНрд░реАрди рдХреА рдЪреМрдбрд╝рд╛рдИ рдФрд░ рдКрдБрдЪрд╛рдИ, рдХреНрд░рдорд╢рдГ, рдЯрд┐рдХ - рдорд┐рд▓реАрд╕реЗрдХрдВрдб рдХреА рд╕рдВрдЦреНрдпрд╛ рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рдлреНрд░реЗрдо рд╕реНрдХреНрд░реАрди рдкрд░ рдЯрд┐рдХрд╛ рд░рд╣реЗрдЧрд╛ред
рдЕрдм рдЪрд▓рд┐рдП рдЗрдирдкреБрдЯреНрд╕ рдкрд░ рдлреИрд╕рд▓рд╛ рдХрд░рддреЗ рд╣реИрдВред рдмрд╛рд╣рд░реА рджреБрдирд┐рдпрд╛ рд╕реЗ, рдХреЗрд╡рд▓ рджреЛ рдШрдЯрдирд╛рдПрдВ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЖрдПрдВрдЧреА: рдПрдХ рдХреБрдВрдЬреА рдкреНрд░реЗрд╕ рдФрд░ рдПрдХ рдШрдбрд╝реА рд╕рдВрдХреЗрддред рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдШрдЯрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ рджреЛ "рд╕реНрд▓реЙрдЯ" рдХреА рдЬрд░реВрд░рдд рд╣реИ рдФрд░ рд╡реЗ newAddHandler рдлрд╝рдВрдХреНрд╢рди рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдП рдЧрдП рд╣реИрдВ:
main :: IO () main = withInit [InitEverything] $ do initScreen sources <- (,) <$> newAddHandler <*> newAddHandler network <- compile $ setupNetwork sources actuate network eventLoop sources network
SetupNetwork рдореЗрдВ, рдЗрд╡реЗрдВрдЯ рдФрд░ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рдПрдХ "рдиреЗрдЯрд╡рд░реНрдХ" рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рд╕рдВрдХрд▓рди NetworkNescription рдХреЛ EventNetwork рдореЗрдВ рд╕рдВрдХрд▓рд┐рдд рдХрд░реЗрдЧрд╛, рдФрд░ рдЗрд╕реЗ рд▓реЙрдиреНрдЪ рдХрд░реЗрдЧрд╛ред рдИрд╡реЗрдВрдЯ рд░рд┐рд╕реЗрдкрд░реНрд╕ рд╕реЗ рдорд╕реНрддрд┐рд╖реНрдХ рдХреЛ рд╕рд┐рдЧреНрдирд▓ рдХреА рддрд░рд╣, рдИрд╡реЗрдВрдЯрдмреНрд▓реВрдк рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдиреЗрдЯрд╡рд░реНрдХ рдХреЛ рднреЗрдЬрд╛ рдЬрд╛рдПрдЧрд╛ред
eventLoop :: (EventSource SDLKey, EventSource Word32) -> EventNetwork -> IO () eventLoop (essdl, estick) network = loop 0 Nothing where loop lt k = do s <- pollEvent t <- getTicks case s of (KeyDown (Keysym key _ _)) -> loop t (Just key) NoEvent -> do maybe (return ()) (fire essdl) k fire estick t loop t Nothing _ -> when (s /= Quit) (loop tk)
рдпрд╣ рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХрд╛ "рд░рд┐рд╕реЗрдкреНрдЯрд░" рд╣реИред рдЖрдЧ Essdl - рдЕрдЧрд░ рдХреЛрдИ рджрдмрд╛рдпрд╛ рдЧрдпрд╛ рдерд╛, рддреЛ рдЪрд╛рдмреА рдХреЗ рдирд╛рдо рд╡рд╛рд▓реЗ рдирд┐рдмрдВрдз рдХрд╛рд░реНрдпрдХреНрд░рдо рдореЗрдВ рдЖрдЧ рд▓рдЧ рдЬрд╛рддреА рд╣реИред рдПрд╕реНрдЯреНрд░рд┐рдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреА рдкрд░рд╡рд╛рд╣ рдХрд┐рдП рдмрд┐рдирд╛ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреА рд╢реБрд░реБрдЖрдд рд╕реЗ рд╕рдордп рд╡рд╣рди рдХрд░рддрд╛ рд╣реИред
рдпрд╣рд╛рдБ, рд╡реИрд╕реЗ, EventSource рд╕реЗ рд╕рдВрдХреНрд░рдордг рд╣реИ, рдЬреЛ AddAandler рдореЗрдВ, NewAddHandler рджреЗрддрд╛ рд╣реИ:
type EventSource a = (AddHandler a, a -> IO ()) addHandler :: EventSource a -> AddHandler a addHandler = fst fire :: EventSource a -> a -> IO () fire = snd
рдЕрдм рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рднрд╛рдЧ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ: рдШрдЯрдирд╛рдУрдВ рдХреЗ рдиреЗрдЯрд╡рд░реНрдХ рдХрд╛ рд╡рд░реНрдгрдиред
setupNetwork :: forall t. (EventSource SDLKey, EventSource Word32) -> NetworkDescription t () setupNetwork (essdl, estick) = do
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рд╣рдореЗрдВ рдЙрди рдЯрд╛рдЗрдорд░ рдФрд░ рдХреАрдмреЛрд░реНрдб рдИрд╡реЗрдВрдЯ рд╕реЗ рдЗрд╡реЗрдВрдЯ рдорд┐рд▓рддреЗ рд╣реИрдВ, рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдордиреЗ рдЗрд╡реЗрдВрдЯрдСрд▓реЙрдк рдореЗрдВ рдирд┐рдХрд╛рд▓ рджрд┐рдпрд╛ рдерд╛ред
let ekey = filterE (flip elem [SDLK_DOWN, SDLK_UP, SDLK_LEFT, SDLK_RIGHT]) esdl moveSnake :: SDLKey -> Snake -> Snake moveSnake ks = case k of SDLK_UP -> moveTo (x, y-1) s SDLK_DOWN -> moveTo (x, y+1) s SDLK_LEFT -> moveTo (x-1, y) s SDLK_RIGHT -> moveTo (x+1, y) s where (x, y) = head s
рдЕрдм рдПрдХ рдРрд╕реА рдШрдЯрдирд╛ рдмрдирд╛рддреЗ рд╣реИрдВ рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рддреАрд░ рдХреЛ рджрдмрд╛рддреЗ рд╣реБрдП - рд╣рдореЗрдВ рдЕрдиреНрдп рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рд╢рд╛рдпрдж рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЕрдиреБрдорд╛рди рд▓рдЧрд╛ рдЪреБрдХреЗ рд╣реИрдВ, рдлрд╝рд┐рд▓реНрдЯрд░E рдЙрди рдШрдЯрдирд╛рдУрдВ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рд╡рд┐рдзреЗрдп рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдирд╣реАрдВ рдХрд░рддреА рд╣реИрдВред MoveSnake рдХреЗрд╡рд▓ рджрдмрд╛рдП рдЧрдП рд╕рд╛рдБрдк рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╕рд╛рдБрдк рдХреЛ рд╣рд┐рд▓рд╛рддрд╛ рд╣реИред
brandom <- fromPoll randomFruits -- Snake let bsnake :: Behavior t Snake bsnake = accumB startingSnake $ (const startingSnake <$ edie) `union` (moveSnake <$> ekey) `union` (keepMoving <$ etick) `union` ((\s -> s ++ [last s]) <$ egot) edie = filterApply ((\s _ -> ifDied s) <$> bsnake) etick
fromPoll рд╡рд╛рд╕реНрддрд╡рд┐рдХ рджреБрдирд┐рдпрд╛ рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдФрд░ рддрд░реАрдХрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЙрд╕ рдЪреАрдЬрд╝ рд╕реЗ рдЕрд▓рдЧ рд╣реИ рдЬреЛ рд╣рдордиреЗ рдкрд╣рд▓реЗ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдерд╛ред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ рд╡реНрдпрд╡рд╣рд╛рд░ рдорд┐рд▓рддрд╛ рд╣реИ, рдИрд╡реЗрдВрдЯ рдирд╣реАрдВред рдФрд░ рджреВрд╕рд░реА рдмрд╛рдд, fromPoll рдореЗрдВ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдорд╣рдВрдЧреА рдирд╣реАрдВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╡реЗрд░рд┐рдПрдмрд▓ рдХреЗ рд╕рд╛рде рдпреБрдЧреНрдорд┐рдд рдХреВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реИред
рдЖрдЧреЗ, рд╣рдо рд╕рдВрдЪрдп рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реБрдП рд╕рд╛рдБрдк рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ (рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╕рд╛рдБрдк рдХрд╛ рдкреНрд░рдХрд╛рд░ рдХреЗрд╡рд▓ рд╡реНрдпрд╡рд╣рд╛рд░ рд╕рд╛рдБрдк рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд╡реНрдпрд╡рд╣рд╛рд░ рдЯреА рд╕рд╛рдВрдкред рдЗрд╕рдХрд╛ рдЧрд╣рд░рд╛ рдЕрд░реНрде рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдореЗрдВ рдЬрд╛рдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ)ред
рд╕рдВрдЪрдп "рдШрдЯрдирд╛рдУрдВ рдФрд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдореВрд▓реНрдп рд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░" рдПрдХрддреНрд░ рдХрд░рддрд╛ рд╣реИ:
accumB :: a -> Event t (a -> a) -> Behavior ta
рдпрд╣реА рд╣реИ, рдореЛрдЯреЗ рддреМрд░ рдкрд░, рдЬрдм рдХреЛрдИ рдШрдЯрдирд╛ рд╣реЛрддреА рд╣реИ, рддреЛ рдЙрд╕рдХреЗ рдЕрдВрджрд░ рдХрд╛ рдлрд╝рдВрдХреНрд╢рди рд╡рд░реНрддрдорд╛рди рдореВрд▓реНрдп рдкрд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:
accumB "x" [(time1,(++"y")),(time2,(++"z"))]
рдПрдХ рд╡реНрдпрд╡рд╣рд╛рд░ рдмрдирд╛рдПрдЧрд╛, рдЬреЛ time1 рдкрд░ "xy" рдХреЛ рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рд░рдЦреЗрдЧрд╛, рдФрд░ time2 - "xyz" рдкрд░ред
рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдПрдХ рдФрд░ рд╕рдорд╛рд░реЛрд╣ рдЕрдЬреНрдЮрд╛рдд рд╣реИред рдпрд╣ рдШрдЯрдирд╛рдУрдВ рдХреЛ рдПрдХ рдореЗрдВ рдЬреЛрдбрд╝рддрд╛ рд╣реИ (рдпрджрд┐ рджреЛ рдШрдЯрдирд╛рдПрдВ рдПрдХ рд╕рд╛рде рд╣реБрдИрдВ, рддреЛ рд╕рдВрдШ рдкрд╣рд▓реЗ рддрд░реНрдХ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рджреЗрддрд╛ рд╣реИ)ред
рдЕрдм рд╣рдо рд╕рдордЭ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ bsnake рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╕рд╛рдБрдк рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рдмрд░рд╛рдмрд░ рд╣реИ, рдФрд░ рдлрд┐рд░ рдЗрд╕рдХреЗ рд╕рд╛рде рдХрдИ рдкрд░рд┐рд╡рд░реНрддрди рд╣реЛрддреЗ рд╣реИрдВ:
- рдпрджрд┐ рд╡рд╣ рдорд░ рдЧрдИ рддреЛ рд╡рд╣ рд╢реБрд░реБрдЖрдд рдореЗрдВ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рддреА рд╣реИ (рдПрдбреА рдЗрд╡реЗрдВрдЯ)
- рддреАрд░ рдХреЛ рджрдмрд╛рдиреЗ рдкрд░ рдореБрдбрд╝рддрд╛ рд╣реИред
- рд╕рд┐рдЧреНрдирд▓ рдкрд░ рдЖрдЧреЗ рдмрдврд╝рдирд╛ рдЬрд╛рд░реА рд╣реИ
- рдФрд░ рдмрдврд╝рддрд╛ рд╣реИ рдЕрдЧрд░ рдЙрд╕рдиреЗ рдлрд▓ рдЦрд╛ рд▓рд┐рдпрд╛ (рдИрдЧреЛ рдЗрд╡реЗрдВрдЯ)
рд╕рд╛рдВрдк рдХреЗ рдореГрдд рд╣реЛрдиреЗ рдкрд░ рдИрдбреА рдХреА рдШрдЯрдирд╛ рдХреЛ рдирд┐рдХрд╛рд▓ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЗрд╕реЗ рдлрд╝рд┐рд▓реНрдЯрд░рдПрдкреНрд▓реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╣рд╛рд╕рд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:
filterApply :: Behavior t (a -> Bool) -> Event ta -> Event ta
рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдЙрди рдШрдЯрдирд╛рдУрдВ рдХреЛ рдЕрдирд╕реБрдирд╛ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рдЕрдВрджрд░ рд╡рд┐рдзреЗрдп рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред рдЬреИрд╕рд╛ рдХрд┐ рдирд╛рдо рд╕реЗ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ, рдпрд╣ рдХреБрдЫ рдРрд╕рд╛ рд╣реИ рдЬреИрд╕реЗ рдлрд╝рд┐рд▓реНрдЯрд░ + рд▓рд╛рдЧреВ рдХрд░реЗрдВред
рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдо рдХрд┐рддрдиреА рдмрд╛рд░ рдХрд┐рд╕реА рдХрд╛рд░реНрдп рдХреЛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░рд┐рдпрд▓ рдлрдВрдХреНрд╢рдирд▓рд░реНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред
рдЕрдм рдлрд▓ рдкрд░ рдЪрд▓рддреЗ рд╣реИрдВ:
-- Fruits bfruit :: Behavior t Pos bfruit = stepper (hdth `div` 2, wdth `div` 2) (brandom <@ egot) egot = filterApply ((\fsr _ -> elem fs && notElem rs) <$> bfruit <*> bsnake <*> brandom) etick
рдмреНрд░реИрдВрдбреЛрдо рдореЗрдВ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХреЗ рд╕рд╛рде рдПрдХ рдирдпрд╛ рдлрд▓ рджрд┐рдЦрд╛рдИ рджреЗрддрд╛ рд╣реИ рдЬреИрд╕реЗ рд╣реА рд╕рд╛рдВрдк рдиреЗ рд╡рд░реНрддрдорд╛рди рдХреЛ рдЗрдХрдЯреНрдард╛ рдХрд┐рдпрд╛ рд╣реИред рдХреЙрдореНрдмрд┐рдиреЗрдЯрд░ <@ "рдИрд╡реЗрдВрдЯ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреА рд╕рд╛рдордЧреНрд░реА" рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рддреН, рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдИрдЧреЙрдЯ рдШрдЯрдирд╛ рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдмреНрд░реИрдВрдбрдо рд╕реЗ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рд╕рдордиреНрд╡рдп рджреНрд╡рд╛рд░рд╛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рд╕реНрдЯреЗрдкрд░ рдлрдВрдХреНрд╢рди, рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдирдпрд╛, рдИрд╡реЗрдВрдЯреНрд╕ рдФрд░ рд╢реБрд░реБрдЖрддреА рдореВрд▓реНрдп рд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдмрдирд╛рддрд╛ рд╣реИ, рдФрд░ рд╕рдВрдЪрдп рд╕реЗ рдЗрд╕рдХрд╛ рдПрдХрдорд╛рддреНрд░ рдЕрдВрддрд░ рдпрд╣ рд╣реИ рдХрд┐ рдирдпрд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рдИрд╡реЗрдВрдЯ рдкрд┐рдЫрд▓реЗ рдкрд░ рдирд┐рд░реНрднрд░ рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред
рдЕрд╣рдВрдХрд╛рд░ рдШрдЯрдирд╛ рдЙрд╕ рдЯрд╛рдЗрдорд░ рд╕рд┐рдЧреНрдирд▓ рдкрд░ рд╢реБрд░реВ рд╣реЛрддреА рд╣реИ рдЬрдм рд╕рд╛рдВрдк рдиреЗ рдлрд▓ рдПрдХрддреНрд░ рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рдПрдХ рдирдпрд╛ рдлрд▓ рдЙрд╕рдХреЗ рд╢рд░реАрд░ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред
-- Counter ecount = accumE 0 $ ((+1) <$ egot) `union` ((const 0) <$ edie)
ecount рдмрдврд╝рддреЗ рд╣реБрдП рдмрд┐рдВрджреБрдУрдВ рдХреА рдПрдХ рдШрдЯрдирд╛ рд╣реИред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЕрдиреБрдорд╛рди рд▓рдЧрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдПрдХ рдШрдЯрдирд╛ рдПрдХ рд╡реНрдпрд╡рд╣рд╛рд░ рдмрдирд╛рддрд╛ рд╣реИ, рди рдХрд┐ рдПрдХ рд╡реНрдпрд╡рд╣рд╛рд░ред рдХрд╛рдЙрдВрдЯрд░ рдХреЛ рдИрдЧреЛ рдЗрд╡реЗрдВрдЯ рдореЗрдВ рдПрдХ-рдПрдХ рдХрд░рдХреЗ рдмрдврд╝рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рдПрдбреА рдкрд░ рд╢реВрдиреНрдп рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
let edraw = apply ((,,) <$> bsnake <*> bfruit) etick
edraw рдХреЛ рд╣рд░ рдЯрд╛рдЗрдорд░ рд╕рд┐рдЧреНрдирд▓ рдкрд░ рдЯреНрд░рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЗрд╕рдореЗрдВ рд╕рд╛рдБрдк рдФрд░ рдлрд▓ рдХреА рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рд╣реЛрддреА рд╣реИред
рдЕрдм рдорд╛рдорд▓рд╛ рдЫреЛрдЯрд╛ рд╣реИ: рд╕реНрдХреНрд░реАрди рдкрд░ рдЫрд╡рд┐ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВред
reactimate $ fmap drawScreen edraw reactimate $ fmap (flip setCaption [] . (++) "Snake. Points: " . show) ecount
рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдлрд╝рдВрдХреНрд╢рди рдХрд┐рд╕реА рдИрд╡реЗрдВрдЯ рд╕реЗ рдПрдХ IO рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреЛ рдирд┐рдХрд╛рд▓рддрд╛ рд╣реИред рдбреНрд░рд╛рд╕реНрдХреНрд░реАрди рд╕реНрдХреНрд░реАрди рдЦреАрдВрдЪрддрд╛ рд╣реИ, рдФрд░ рд╕реЗрдЯрдХреИрдкреНрд╢рди рд╡рд┐рдВрдбреЛ рдХрд╛ рдирд╛рдо рдмрджрд▓рддрд╛ рд╣реИред
рдпрд╣ setupNetwork рдкреВрд░рд╛ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд╣рдо рдХреЗрд╡рд▓ рд▓рд╛рдкрддрд╛ рдлрд╝рдВрдХреНрд╢рди рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред
рд╕реНрдХреНрд░реАрди рдЖрд░рдВрднреАрдХрд░рдг:
initScreen = do glSetAttribute glDoubleBuffer 1 screen <- setVideoMode screenWidth screenHeight screenBpp [OpenGL] setCaption "Snake. Points: 0" [] clearColor $= Color4 0 0 0 0 matrixMode $= Projection loadIdentity ortho 0 (fromIntegral screenWidth) (fromIntegral screenHeight) 0 (-1) 1 matrixMode $= Modelview 0 loadIdentity
рд░реИрдВрдбрдо рд╕реНрдерд┐рддрд┐ рдЬрдирд░реЗрдЯрд░:
randomFruits :: IO Pos randomFruits = (,) <$> (randomRIO (0, wdth-1)) <*> (randomRIO (0, hdth-1))
рдареАрдХ рд╣реИ, рдЕрдВрдд рдореЗрдВ, рдкреНрд░рддрд┐рдкрд╛рджрди рдХрд╛рд░реНрдп:
showSquare :: (GLfloat, GLfloat, GLfloat, GLfloat) -> Pos -> IO () showSquare (r, g, b, a) (x, y) = do -- Move to offset translate $ Vector3 (fromIntegral x*10 :: GLfloat) (fromIntegral y*10) 0 -- Start quad renderPrimitive Quads $ do -- Set color color $ Color4 rgba -- Draw square vertex $ Vertex3 (0 :: GLfloat) 0 0 vertex $ Vertex3 (10 :: GLfloat) 0 0 vertex $ Vertex3 (10 :: GLfloat) 10 0 vertex $ Vertex3 (0 :: GLfloat) 10 0 loadIdentity showFruit :: Pos -> IO () showFruit = showSquare (0, 1, 0, 1) showSnake :: Snake -> IO () showSnake = mapM_ (showSquare (1, 1, 1, 1)) drawScreen (s, f, t) = do clear [ColorBuffer] showSnake s showFruit f glSwapBuffers t' <- getTicks when ((t'-t) < ticks) (delay $ ticks - t' + t)
рд╡рд╣ рд╕рдм рд╣реИред рд╕рдВрдХрд▓рди рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА: рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓-рдХреЗрд▓рд╛, рдУрдкреЗрдВрдЧреНрд▓, рдПрд╕рдбреАрдПрд▓ред рдпрд╣рд╛рдВ рд╕реЗ рдЖрдк рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреА рд╕реЛрд░реНрд╕ рдлрд╛рдЗрд▓реНрд╕ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
minus.com/mZyZpD4Hx/1fрдирд┐рд╖реНрдХрд░реНрд╖
рдПрдХ рдЫреЛрдЯреЗ рд╕реЗ рдЦреЗрд▓ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдореИрдВрдиреЗ рдПрдлрдЖрд░рдкреА рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рдмреБрдирд┐рдпрд╛рджреА рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдХреЛ рджрд┐рдЦрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА: рдШрдЯрдирд╛рдУрдВ рдФрд░ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЗ рдпрд╛рдВрддреНрд░рд┐рдХреА рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддреЗ рд╣реБрдП, рдЗрдирдкреБрдЯ рдФрд░ рдЖрдЙрдЯрдкреБрдЯ рдбреЗрдЯрд╛ рдХреЛ рдЕрд▓рдЧ рдХрд░рдирд╛ред рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдХ рд╕рд░рд▓ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЗ рд╕рд╛рде, рдЖрдк рдПрдлрдЖрд░рдкреА рдХреЗ рдлрд╛рдпрджреЗ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЦреЗрд▓ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рдХрд╛рд░ рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рдХрд░рдирд╛ рдерд╛, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдордиреЗ рдЗрд╕ рдкреНрд░рддрд┐рдорд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдмрд┐рдирд╛ рдХрд┐рдпрд╛ рд╣реЛрдЧрд╛ред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдпрд╣ рд▓реЗрдЦ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рдЕрдзреНрдпрдпрди рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ рдФрд░ рдЗрд╕рдХреА рд╕рдордЭ рдХреЛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдмрдирд╛рдПрдЧрд╛ред
рд╕рдВрджрд░реНрдн
hackage.haskell.org/package/reactive-banana -
рд╣реИрдХ рдкрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓-рдХреЗрд▓рд╛
github.com/HeinrichApfelmus/reactive-banana - github рдкрд░ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реАред рдЗрд╕рдХреЗ рдЙрджрд╛рд╣рд░рдг рд╣реИрдВред