{"id":15616800,"url":"https://github.com/paluh/purescript-boomerang","last_synced_at":"2026-02-13T05:02:45.279Z","repository":{"id":58242409,"uuid":"54780941","full_name":"paluh/purescript-boomerang","owner":"paluh","description":"Invertible parsers + useful combinators - clone of haskell boomerang library","archived":false,"fork":false,"pushed_at":"2019-11-07T00:49:03.000Z","size":74,"stargazers_count":7,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-06T17:43:50.429Z","etag":null,"topics":["boomerang","invertible-parsers","purescript","routing"],"latest_commit_sha":null,"homepage":"","language":"PureScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paluh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-26T13:44:49.000Z","updated_at":"2020-09-23T23:26:16.000Z","dependencies_parsed_at":"2022-08-31T04:40:29.051Z","dependency_job_id":null,"html_url":"https://github.com/paluh/purescript-boomerang","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/paluh/purescript-boomerang","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paluh%2Fpurescript-boomerang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paluh%2Fpurescript-boomerang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paluh%2Fpurescript-boomerang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paluh%2Fpurescript-boomerang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paluh","download_url":"https://codeload.github.com/paluh/purescript-boomerang/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paluh%2Fpurescript-boomerang/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29396847,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-13T04:26:15.637Z","status":"ssl_error","status_checked_at":"2026-02-13T04:16:29.732Z","response_time":78,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["boomerang","invertible-parsers","purescript","routing"],"created_at":"2024-10-03T07:22:05.585Z","updated_at":"2026-02-13T05:02:45.263Z","avatar_url":"https://github.com/paluh.png","language":"PureScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## purescript-boomerang - typesafe bidirectional routing\n\nThis library implements invertible parsers (it is clone of haskell boomerang library). With these (semi)isomorphic stuctures and provided combinators it's quite easy to define bidirectional web routes. You can check __purescript-routing-bob__ for example routing library build upon boomerangs.\n\n\n## Design\n\nThis library is build upon a really simple approach to parsers/serializers. I'm using Haskell tuple notation in the following psudocode snippets to simplify reading.\n\nWe can think of parsers as a functions which take an input and result from the provious steps of parsing and give back the result and the rest of input:\n\n  ```purescript\n  prs :: (a, tok) -\u003e (b, tok)\n  ```\n\nSo `tok` on the left hand side of the function represents input stream (for example `String` or list of `String`s) but on the right hand side it represents unconsumed part of the input.\n`a` is a result from previous steps of parsing and `b` is a result of current parsing step build upon `a` value.\n\nThis type is really general and composable - it composes just by function composition:\n\n  ```purescript\n  ((b, tok) -\u003e (c, tok)) \u003c\u003c\u003c ((a, tok) -\u003e (b, tok)):: (a, tok) -\u003e (c, tok)\n  ```\nWhat we really have here is a Kleisly Arrow of the well known and beloved monadic parser of type: `tok -\u003e (a, tok)`.\n\nWhat about serializer. With the above approach to parsing we can easily reverse the function arrow and get:\n\n  ```purescript\n  (b, tok) -\u003e (a, tok)\n  ```\n\nThese types are really isomorphic but the main \"mechanical\" difference is that \"`tok` should grow\" from left to right and `a` should be subpart of our staring `b` in the case of a serializer. What is even more important is that this type composes as easily as our parser type because it is also a simple function ;-)\n\nFrom these two types we can build our Boomerang type - it is just a product of them. Let's write some real Purescript:\n\n  ```purescript\n  newtype Boomerang tok a b =\n    Boomerang\n      { prs :: { tok :: tok, val :: a } -\u003e { tok :: tok, val :: b }\n      , ser :: { tok :: tok, val :: b } -\u003e { tok :: tok, val :: a }\n      }\n  ```\n\nAnd we can compose them by composing `prs` and `ser` but in \"different directions\" (this is \"Product Category\" AFAIK). Here is `Semigroupoid` instance:\n\n  ```purescript\n  instance semigroupoidBoomerang :: Semigroupoid (Boomerang tok) where\n    compose (Boomerang b1) (Boomerang b2) =\n      Boomerang\n        { prs: b1.prs \u003c\u003c\u003c b2.prs\n        , ser: b2.ser \u003c\u003c\u003c b1.ser\n        }\n  ```\nTo be honest this library uses specialized version (so less powerfull) of a parser type:\n\n  ```purescript\n  prs' :: tok -\u003e ((a -\u003e b), tok)\n  ```\n\nSuch a parser can be easily converted into previous form (but not the other way around):\n\n  ```purescript\n  prs :: (tok -\u003e ((a -\u003e b), tok)) -\u003e ((tok, a) -\u003e (tok, b))\n  prs p = \\(tok, a) -\u003e\n    let (a2b, tok') = p tok\n    in (a2b a, tok')\n  ```\n\nThis representation allows us to use standard `Parser` type (from `purescript-parsing`) - all we have is:\n\n`type Parser tok a b = Parser tok (a -\u003e b)`.\n\n\nThis library also uses different serializer type internally:\n\n  ```purescript\n  ser' :: b -\u003e ((tok -\u003e tok), a)\n  ```\n\nIt can also be converted to our previous representation:\n\n  ```purescript\n  ser :: (b -\u003e ((tok -\u003e tok), a)) -\u003e ((tok, b) -\u003e (tok, a))\n  ser s = \\(tok, b) -\u003e\n    let (tok2tok, a) = s b\n    in (tok2tok tok, a)\n  ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaluh%2Fpurescript-boomerang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaluh%2Fpurescript-boomerang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaluh%2Fpurescript-boomerang/lists"}