{"id":16663420,"url":"https://github.com/turion/rhine","last_synced_at":"2025-10-11T05:35:46.861Z","repository":{"id":12424216,"uuid":"71767045","full_name":"turion/rhine","owner":"turion","description":"Haskell Functional Reactive Programming framework with type-level clocks","archived":false,"fork":false,"pushed_at":"2024-05-22T08:41:57.000Z","size":3252,"stargazers_count":106,"open_issues_count":100,"forks_count":21,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-05-22T12:10:15.487Z","etag":null,"topics":["clock","frp","hacktoberfest","haskell","haskell-library","resampling","scheduling"],"latest_commit_sha":null,"homepage":"http://hackage.haskell.org/package/rhine","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/turion.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"Contributing.md","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":"2016-10-24T08:15:58.000Z","updated_at":"2024-06-01T21:29:08.870Z","dependencies_parsed_at":"2023-11-21T10:41:12.519Z","dependency_job_id":"697cf3a4-9409-47ed-b6be-a81fca6ce220","html_url":"https://github.com/turion/rhine","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turion%2Frhine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turion%2Frhine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turion%2Frhine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turion%2Frhine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/turion","download_url":"https://codeload.github.com/turion/rhine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248208689,"owners_count":21065205,"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":["clock","frp","hacktoberfest","haskell","haskell-library","resampling","scheduling"],"created_at":"2024-10-12T10:40:55.807Z","updated_at":"2025-10-11T05:35:41.837Z","avatar_url":"https://github.com/turion.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# README\n--------\n\n[![Build Status](https://github.com/turion/rhine/actions/workflows/ci.yml/badge.svg)](https://github.com/turion/rhine/actions/workflows/ci.yml)\n[![Version on Hackage](https://img.shields.io/hackage/v/rhine.svg)](https://hackage.haskell.org/package/rhine)\n\nRhine is a library for synchronous and asynchronous Functional Reactive Programming (FRP).\nIt separates the aspects of clocking, scheduling and resampling\nfrom each other, and ensures clock-safety on the type level.\n\n## Recent breakage?\n\nConfused because some examples from the article don't work anymore?\nRhine went through a few bigger API simplifications and changes.\nIf this broke your code, have a look at [the versions readme](./versions.md) to fix it.\n\n## Concept\n\nComplex reactive programs often process data at different rates.\nFor example, games, GUIs and media applications\nmay output audio and video signals, or receive\nuser input at unpredictable times.\nCoordinating these different rates is a hard problem in general.\nIf not enough care is taken, buffer underruns and overflows, space and time leaks,\naccidental synchronisation of independent sub-systems,\nand concurrency issues, such as deadlocks, may all occur.\n\nRhine tackles these problems by annotating\nthe signal processing components with clocks,\nwhich hold the information when data will be\ninput, processed and output.\nDifferent components of the signal network\nwill become active at different times, or work\nat different rates. If components running under different clocks need to communicate, it\nhas to be decided when each component becomes\nactive (\"scheduling\"), and how data is\ntransferred between the different rates (\"resampling\").\nRhine separates all these aspects from each\nother, and from the individual signal processing of each subsystem.\nIt offers a flexible API to all of them and implements several\nreusable standard solutions. In the places\nwhere these aspects need to intertwine, typing\nconstraints on clocks come into effect, enforcing clock safety.\n\n## Example\n\nA typical example,\nwhich can be run as `cd rhine-examples/ \u0026\u0026 cabal run Demonstration`,\n(or using nix flakes with `nix develop` followed `cabal run Demonstration`),\nwould be:\n\n```haskell\n  -- | Create a simple message containing the time stamp since initialisation,\n  --   for each tick of the clock.\n  --   Since 'createMessage' works for arbitrary clocks (and doesn't need further input data),\n  --   it is a 'Behaviour'.\n  --   @time@ is the 'TimeDomain' of any clock used to sample,\n  --   and it needs to be constrained in order for time differences\n  --   to have a 'Show' instance.\n  createMessage\n    :: (Monad m, Show (Diff time))\n    =\u003e String\n    -\u003e Behaviour m time String\n  createMessage str\n    =   timeInfoOf sinceInit \u003e-\u003e arr show\n    \u003e-\u003e arr ((\"Clock \" ++ str ++ \" has ticked at: \") ++)\n\n  -- | Output a message /every second/ (= every 1000 milliseconds).\n  --   Let us assume we want to assure that 'printEverySecond'\n  --   is only called every second,\n  --   then we constrain its type signature with the clock @Millisecond 1000@.\n  printEverySecond :: Show a =\u003e ClSF IO (Millisecond 1000) a ()\n  printEverySecond = arrMCl print\n\n  -- | Specialise 'createMessage' to a specific clock.\n  ms500 :: ClSF IO (Millisecond 500) () String\n  ms500 = createMessage \"500 MS\"\n\n\n  ms1200 :: ClSF IO (Millisecond 1200) () String\n  ms1200 = createMessage \"1200 MS\"\n\n  -- | Create messages every 500 ms and every 1200 ms,\n  --   collecting all of them in a list,\n  --   which is output every second.\n  main :: IO ()\n  main = flow $\n    ms500 @@ waitClock            --  a Rhine = a ClSF in the context of a Clock\n    |@|                           --  compose 2 Rhines in parallel\n    ms1200 @@ waitClock           --  a Rhine at a different clock\n    \u003e-- collect --\u003e               --  buffer results from both Rhines into a list\n    printEverySecond @@ waitClock --  the final Rhine\n\n  -- | Uncomment the following for a type error (the clocks don't match):\n\n  -- typeError = ms500 \u003e\u003e\u003e printEverySecond\n```\n\n## This repository\n\n* `rhine/`: The main library, which is also mirrored on hackage.\n* `rhine-gloss/`: A wrapper library to [`gloss`](https://hackage.haskell.org/package/gloss), a functional OpenGL library.\n* `rhine-bayes/`: A library for stochastic processes and online machine learning, using [`monad-bayes`](https://hackage.haskell.org/package/monad-bayes).\n* `rhine-terminal/`: A wrapper library to [`terminal`](https://hackage.haskell.org/package/terminal), a library to write terminal applications.\n* `rhine-examples/`: Different examples as a starting point to learn Rhine.\n\n## Learn Rhine\n\nThe recommended way to start is the https://github.com/turion/rhine-koans/ tutorial.\nIt leads you through basic and advanced Rhine concepts by solving many self-contained puzzles.\n\nFor a quick reference of the most important functions, operators, and concepts,\nsee the [cheatsheet](https://github.com/turion/rhine/blob/master/CHEATSHEET.md).\n\n### Documentation resources\n\n* https://www.tweag.io/blog/2023-10-12-rhine-bayes/: A blog post about how to do machine learning with Rhine.\n* https://github.com/turion/rhine/tree/master/rhine-examples/src: Many self-contained examples showcasing typical Rhine concepts in an idiomatic style.\n* The research article [Rhine: FRP with Type-Level Clocks](https://www.manuelbaerenz.de/files/Rhine.pdf) is not quite up to date with the most recent changes,\n  but gives a good overview behind the concepts and design ideas.\n* [`hackage`](https://hackage.haskell.org/package/rhine): Reference documentation\n* [`stackage`](https://www.stackage.org/package/rhine)\n* https://github.com/turion/rhine-tutorial: Presentation and tutorial app\n* https://github.com/turion/sonnendemo: Demo application\n\n\n## FAQ\n\n* Why does my blocking code, e.g. `arrMCl readLn`, behave [erratically](https://github.com/turion/rhine/issues/153)?\n\n[`Clock`](https://hackage.haskell.org/package/rhine/docs/FRP-Rhine-Clock.html)s must be the only things that block a thread, not [`ClSF`](https://hackage.haskell.org/package/rhine/docs/FRP-Rhine-ClSF-Core.html#t:ClSF)s. So for example, you can fix:\n\n```haskell\narrMCl readLn\n```\n\nby using:\n\n```haskell\ntagS \u003e\u003e\u003e arr read :: ClSF IO StdinClock () Int\n```\n\n[`tagS`](https://hackage.haskell.org/package/rhine/docs/FRP-Rhine.html#v:tagS) contains the string that the [`StdinClock`](https://hackage.haskell.org/package/rhine/docs/FRP-Rhine.html#t:StdinClock) grabbed from `stdin`, and only the clock has been allowed to block the thread!\n\n\n* Can a sampling schedule dynamically change, e.g. depend on a signal?\n\nYes, for instance you could implement a distance-dependent [collision detector](https://github.com/turion/rhine/issues/152).\n\n\n* How to handle slow computations, i.e. computations that take longer than the sample rate?\n\nSeveral [strategies exist](https://github.com/turion/rhine/issues/151) and it depends on your use case.\nFor [`FixedStep`](https://hackage.haskell.org/package/rhine/docs/FRP-Rhine-Clock-FixedStep.html#t:FixedStep) clocks, it won't matter since the execution of the program isn't tied to a realtime clock.\nFor [`ClSF`](https://hackage.haskell.org/package/rhine/docs/FRP-Rhine-ClSF-Core.html#t:ClSF)s running on `UTCTime` clocks, you can execute the slow code in a separate thread and coordinate merging the results back into the signal network.\n\n## Support\n\nAny question about Rhine is welcome.\n\n* You can open a discussion at [Github discussions](https://github.com/turion/rhine/discussions) for a specific question.\n* For general discussions, comments and questions, join the [Matrix channel `#rhine:matrix.org`](https://matrix.to/#/#rhine:matrix.org).\n* If you think you've found a bug, open [an issue in Github](https://github.com/turion/rhine/issues).\n\n## Development\n\nSee [`Contributing.md`](./Contributing.md) for details.\n\n* Rhine usually follows up-to-date GHC versions.\n* Contributions are welcome!\n  There are always a few issues labelled [`help wanted`](https://github.com/turion/rhine/issues?q=state%3Aopen%20label%3A%22help%20wanted%22),\n  in case you're looking for an easy way to get started.\n* Rhine is a beginner-friendly Haskell project!\n  Even if you're new to Haskell and FRP, you can contribute.\n  This is a good place to start contributing to open-source projects.\n  Have a look at issues labelled [`good first issue`](https://github.com/turion/rhine/issues?q=state%3Aopen%20label%3A%22good%20first%20issue%22).\n  If you have questions, don't hesitate to ask on Github.\n\n## Related projects\n\n* https://github.com/turion/rhine-tutorial: Presentation and tutorial app\n* https://github.com/fphh/rhine-ghcjs/:\n  A little browser game written with Rhine and `react-hs`,\n  compiles with `GHCJS` to JavaScript.\n* https://github.com/turion/sonnendemo:\n  An interactive simulation with a GUI version and a console version,\n  using `rhine-gloss`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fturion%2Frhine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fturion%2Frhine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fturion%2Frhine/lists"}