úÎ/µ.A    SafeSafe NoneT[(downcasts a monad to a list of functors.e.g.,isSimpleWorkflow $ getClipboard >>= sendTextNothingQisSimpleWorkflow $ setClipboard "copying..." >> sendKeyChord [HyperModifier] CKeyHJust [SetClipboard "copying..." (),SendKeyChord [HyperModifier] CKey ()] TODO When :  >>> fromJust >>>  ===  Fshows (an inaccurate approximation of) the "static" data flow of some *, by showing its primitive operations (in  do-notation).e.g.:{putStrLn . showWorkflow $ do# sendKeyChord [Command, Shift] BKey delay 1000$ sendKeyChord [Command] DownArrowKey x1 <- currentApplication x2 <- getClipboard3 openURL $ "https://www.google.com/search?q=" <> x2 setClipboard x1 getClipboard:}do& sendKeyChord ([Command,Shift]) (BKey) delay (1000)( sendKeyChord ([Command]) (DownArrowKey) x1 <- currentApplication x2 <- getClipboard1 openURL ("https://www.google.com/search?q={x2}") setClipboard ("{x1}") x3 <- getClipboard return "{x3}"3(note: doesn't print variables as raw strings (cf.  versus Ì), as it doesn't "crystallize" all operations into "symbols", but gives you an idea of the data flow. however, it does correctly track the control flow, even when the variables are used non-sequentially.)B(note: the variables in the code were named to be consistent with gensymf, for readability. but of course the bindings aren't reified, and they could have been named anything)*basically, the monadically-bound variable x1" is shown as if it were literally "{x1}"Š (rather than, the current clipboard contents). a more complicated alternative could be to purely model the state: e.g. a clipboard, with  and  working together, etc.).ŽTODO would be complicated by SendTextTo; unless unit consuctors are distinguished (as sendTextTo =<< currentApplication is kinda Applicative).NoneT[int2keychord -12'[([],MinusKey),([],OneKey),([],TwoKey)]?a (base ten) digit is a number between zero and nine inclusive.digit2keychord 2 ([],TwoKey)digit2keychord -2Nothingdigit2keychord 12Nothing Bthe keychord that would insert the character into the application.#char2keychord '@' :: Maybe KeyChordJust ([ShiftModifier], TwoKey)”some characters cannot be represented as keychordes, like some non-printable characters (in arbitrary applications, not just the terminal emulator):$char2keychord '\0' :: Maybe KeyChordNothingscase char2keychord c of { Just ([],_) -> True; Just ([ShiftModifier],_) -> True; Nothing -> True; _ -> False } +the character that represents the keychord:5keychord2char ([ShiftModifier], TwoKey) :: Maybe CharJust '@'Msome keychordes cannot be represented as characters, like keyboard shortcuts:-keychord2char ([Command], CKey) :: Maybe CharNothingimport Data.Charimport Data.Maybe*prop> maybe True isAscii (keychord2char k) TODO replace true with redo test    None  None          !"#!"$%&'()%*'(+,-,.'(/'(01*workflow-pure-0.0.0-BEXCEYaD6UYLnN7opWJdECWorkflow.Pure.ExtraWorkflow.Pure.ExecuteWorkflow.Pure.CharWorkflow.Pure.MainWorkflow.Pure.Types Workflow.PurenothingfailedGensymGensymMSimpleWorkflowMisSimpleWorkflow showWorkflow int2keychorddigit2keychord char2keychord keychord2charmainbase Data.DataData GHC.GenericsGenericData.Semigroup SemigroupControl.Category>>> Data.Function&deepseq-1.4.2.0Control.DeepSeqNFData'exceptions-0.8.3-5OTPYzRazb4DJ75sPncYEhControl.Monad.Catch MonadThrowthrowMGHC.BaseJust+workflow-types-0.0.0-4C2lSKxxi5F4cuC75Ls42rWorkflow.Types fromWorkflow_idWorkflow System.IOprintputStrLn SetClipboard GetClipboard