{"id":16334010,"url":"https://github.com/nmattia/butler","last_synced_at":"2025-06-16T07:09:17.994Z","repository":{"id":94700627,"uuid":"113101179","full_name":"nmattia/butler","owner":"nmattia","description":"Butler-suite for typed protocols and state machines","archived":false,"fork":false,"pushed_at":"2017-12-18T21:56:15.000Z","size":27,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-16T03:36:22.936Z","etag":null,"topics":["haskell","protocols","typesafe"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nmattia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-04T22:14:51.000Z","updated_at":"2019-12-13T10:04:49.000Z","dependencies_parsed_at":"2023-04-27T04:45:40.740Z","dependency_job_id":null,"html_url":"https://github.com/nmattia/butler","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nmattia/butler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmattia%2Fbutler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmattia%2Fbutler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmattia%2Fbutler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmattia%2Fbutler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nmattia","download_url":"https://codeload.github.com/nmattia/butler/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmattia%2Fbutler/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260116645,"owners_count":22961065,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["haskell","protocols","typesafe"],"created_at":"2024-10-10T23:37:10.368Z","updated_at":"2025-06-16T07:09:17.972Z","avatar_url":"https://github.com/nmattia.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Butler Suite\n\nThe Butler suite is a set of haskell libraries for implementing state machines\nand protocols.\n\nBuild with:\n\n``` shell\n$ stack build\n```\n\nThis repository contains two libraries and one example:\n\n* [transit](./transit), the library for typed states and transitions\n* [protolol](./protolol), a library built on top of `transit`, focused on\n  protocols\n* [protolol-duplex](./protolol/examples/Duplex.hs), an example usage of\n  `protolol`\n\n## Example\n\nHere is an example protocol:\n\n``` haskell\n-- Defined the transitions between the states (the protocol)\ntype instance Transition Start =\n  S (Either Ping GoodBye) :\u003e (C Pong :\u003e S NominalDiffTime :\u003e Start :\u003c|\u003e\n                              Quit)\ntype instance Transition Quit = Done Quit\n```\n\n\nHere is an example transport implementation for the protocol:\n\n``` haskell\n-- | Bi-directional in process communication: send and receive\ndata Duplex a = Duplex { sendChan :: Chan a, recvChan :: Chan a }\n\n-- | Help for swapping the send and receive channels\nswapDuplex :: Duplex a -\u003e Duplex a\nswapDuplex (Duplex a b) = Duplex b a\n\n-- | Server transport implementation\nserverTransport :: Duplex Message -\u003e Transport Start ServerMapping\nserverTransport c = fix $ \\f -\u003e\n    Transition $\n      sendPingGoodBye c :\u003e (recvPong c :\u003e sendChrono c :\u003e f\n                      :\u003c|\u003e  done)\n\n-- | Client transport implementation\nclientTransport :: Duplex Message -\u003e Transport Start ClientMapping\nclientTransport c = fix $ \\f -\u003e\n    Transition $\n      recvPingGoodBye c :\u003e (sendPong c :\u003e recvChrono c :\u003e f\n                      :\u003c|\u003e  done)\n```\n\nHere are the server and client logic implementations:\n\n``` haskell\nserver :: ServerM Start Quit ()\nserver = flip fix 1 (\\f x -\u003e do\n    transition -- enter the transition of state 'Start'\n    if x \u003c= (5 :: Int)\n    then do\n      t1 \u003c- liftIO getCurrentTime\n      send (Left Ping)\n      route @(C Pong :\u003e S NominalDiffTime :\u003e Start) -- pick a particular route\n      Pong \u003c- receive\n      t2 \u003c- liftIO getCurrentTime\n      send (diffUTCTime t2 t1)\n      liftIO (threadDelay 1000000)\n      f (x + 1) -- loop\n    else do\n      send (Right GoodBye)\n      route @Quit\n    )\n\nclient :: ClientM Start Quit ()\nclient = fix (\\f -\u003e do\n    transition -- enter the transition of state 'Start - client side\n    msg \u003c- receive\n    case msg of\n      Left Ping -\u003e do\n        route @(C Pong :\u003e S NominalDiffTime :\u003e Start)\n        send Pong\n        x \u003c- receive\n        liftIO (putStrLn $ \"Roundtrip took: \" \u003c\u003e show x)\n        f\n      Right GoodBye -\u003e do\n        route @Quit\n        return ()\n    )\n```\n\nHere are the server and client running:\n\n``` haskell\nmain :: IO ()\nmain = do\n    sdup \u003c- Duplex \u003c$\u003e newChan \u003c*\u003e newChan\n    void $ concurrently\n      (evalTransitT server (serverTransport sdup))\n      (evalTransitT client (clientTransport (swapDuplex sdup)))\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnmattia%2Fbutler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnmattia%2Fbutler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnmattia%2Fbutler/lists"}