Closed Globidev closed 9 years ago
I'm not sure about fifo if you want windows compatibility. As of now, you are windows compatible, and it is easy to test. Unless there is a clear ferformance need for fifo, I have the feeling that stdin and stdout are good ideas.
:warning:
I write below how you could give irc Scripters the ability to manipulate life of players in the game you're broascasting via scripts, even if they have absolutely no way to get that data themselves. It will even works for scripts connected remotely to your irc App
one will be able to write
then you can use in your Script:
... -> print $ do
globiLife <- playerLife "globi"
rvionLIfe <- playerLife "rvion"
sendMessage $ (if globiLife > rvionLife then "globi" else "rvion") ++ " has the lead"
replicateM 10 $ sendMessage "hello"
return ()
and the whole expression will just be an AST that the App will evaluate later, with access to playerLife
free monads allows you to decoupe the code and it's evaluation. It allows Script to build an AST with nice syntax and return it to App for App to evaluate it. It also allows you to switch which evaluator to run at runtime.
free-monads allow you to build expressions, and interpret them later. In your case, you could turn
data Action
= SendMessage Channel String
| SendPong String deriving (Show, Read, Eq)
into ( I also add a new action to better show what becomes possible)
data Action next
= SendMessage Channel String next
| SendPong String next
| PlayerLife String (Int -> next)
| Done
deriving (Functor, Show, Read, Eq) -- use DeriveFunctor extension if you don't want to write the functor instance by hand.
the instance looks like that anyway, if you prefer to write it by hand:
instance Functor Action where
fmap f (SendMessage c s next) = SendMessage c s (f next)
fmap f (SendPong s next ) = SendPong s (f next)
fmap f (PlayerLife s nextF ) = PlayerLife s (f . nextF)
fmap f Done = Done
then you
type Script = Free Interaction
then you make your nice dsl builders (not needed, but that will allow you to only export those nice functions to you final user, and he'll have an orgasmic experience):
sendPong :: String -> Script ()
sendPong s = liftF (SendPong s ())
playerLife :: String -> Script Int
playerLife s = liftF (PlayerLife s id)
sendMessage :: Channel -> String -> Script ()
sendMessage s = liftF (SendMessage c s ())
then you can use in your Script:
... -> print $ do
globiLife <- playerLife "globi"
rvionLIfe <- playerLife "rvion"
sendMessage $ (if globiLife > rvionLife then "globi" else "rvion") ++ " has the lead"
replicateM 10 $ sendMessage "hello"
return ()
The amazing part is that all the do bloc here has type Script ()
.
No IO is done, the whole AST is serialized :)
and in can be interpreted in App with an interpreter like that
interpret_v1 :: Script a -> IO a
interpret_v1 prog = case prog of
Free (PlayerLife playerName g) -> do
life <- ..... -- some IO code checking the player Life
interpret (g life)
Free (SendMessage c m next) -> do
Twitch.sendMessage client c m
interpret next
....
see here for more infos: http://www.haskellforall.com/2012/06/you-could-have-invented-free-monads.html
Should be fine for now Will definitely dig into free monads later though
They use a piped stderr (This might be better to use fifos in the future)