{"id":17252032,"url":"https://github.com/ppetr/tie-knot","last_synced_at":"2025-04-14T05:34:44.434Z","repository":{"id":4998437,"uuid":"6156649","full_name":"ppetr/tie-knot","owner":"ppetr","description":"\"Ties the knot\" on a given set of structures that reference each other by keys - replaces the keys with their respective values.","archived":false,"fork":false,"pushed_at":"2012-12-22T07:30:41.000Z","size":172,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-27T19:22:06.582Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ppetr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-10-10T12:04:19.000Z","updated_at":"2020-06-13T16:43:24.000Z","dependencies_parsed_at":"2022-09-12T05:50:33.711Z","dependency_job_id":null,"html_url":"https://github.com/ppetr/tie-knot","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppetr%2Ftie-knot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppetr%2Ftie-knot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppetr%2Ftie-knot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppetr%2Ftie-knot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ppetr","download_url":"https://codeload.github.com/ppetr/tie-knot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248828515,"owners_count":21168057,"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":[],"created_at":"2024-10-15T06:52:51.949Z","updated_at":"2025-04-14T05:34:44.411Z","avatar_url":"https://github.com/ppetr.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tie-knot\n\n\"Ties the knot\" on a given set of structures that reference each other by\nkeys - replaces the keys with their respective values.  Takes `Map k (v k)` and\nconverts into `Map k v'` where `v'` is the fixed point of `v`.\n\nThis is accomplished by functions\n```haskell\ntype RefMap k v = Map k (v k)\n\ntie :: (Ord k, F.Foldable (Base v), Unfoldable v)\n    =\u003e RefMap k (Base v) -\u003e Either (TieError k) (Map k v)\ntie' :: (Ord k, Unfoldable v)\n    =\u003e RefMap k (Base v) -\u003e Map k v\n```\nThe first variant performs consistency checking (this is why it needs\n`Foldable`), the other just fails with an error if a key is missing in the map.\n\n## Examples:\n\n# Alice, Bob and the cat\n\nSuppose that Alice loves Bob and her cat, Bob loves Alice and the cat loves\nonly itself. Imagine that we're reading this information from some kind of a\ntext file, and store the intermediate data into a list. We would like to create\na data structure which would contain these cyclic dependencies:\n\n```haskell\ndata Person = Person { name :: String, loves :: [Person] }\n\n-- Define a variant of Person where the recursive type\n-- is given as a parameter and the embedding function.\n\ndata Person' t = Person' { _name :: String, _loves :: [t] }\ntype instance Base Person = Person'\ninstance Unfoldable Person where\n  embed ~(Person' n ps)    = Person n ps\n\n-- The easisest way to get 'Foldable' + 'Functor' is to implement\n-- 'Traversable' and then just use the default implementations.\ninstance T.Traversable Person' where\n    traverse f (Person' n ns) = Person' n \u003c$\u003e T.traverse f ns\ninstance Functor Person' where\n    fmap = T.fmapDefault\ninstance F.Foldable Person' where\n    foldMap = T.foldMapDefault\n\n-- Let's create a person with cicrular dependencies:\nalice :: Person\nalice = fromJust . Map.lookup \"Alice\" . \n            tie' . Map.fromList . map nameValue $ lst\n  where\n    lst = [ Person' \"Alice\" [\"Bob\", \"cat\"]\n          , Person' \"Bob\"   [\"Alice\"]\n          -- you may disagree, but the cat thinks of itself as Person\n          , Person' \"cat\"   [\"cat\"]\n          ]\n    nameValue loves = (_name loves, loves)\n```\n\n# Circular lists\n\nThere is a well known task of converting a list into a circular structure with\nno beginning/end:\n\n```haskell\ndata DList a = DLNode (DList a) a (DList a)\n\nmkDList :: [a] -\u003e DList a\n```\n\nWe can accomplish this using tie-knot by simply numbering the fields of a list\nand then letting the library to tie the knot:\n\n```haskell\ndata DList' a t = DLNode' t a t\ntype instance Base (DList a) = DList' a\ninstance Unfoldable (DList a) where\n  embed ~(DLNode' u x v) = DLNode u x v\n\ninstance Functor (DList' n) where\n    fmap = T.fmapDefault\ninstance T.Traversable (DList' n) where\n    traverse f (DLNode' u n v) = DLNode' \u003c$\u003e f u \u003c*\u003e pure n \u003c*\u003e f v\ninstance F.Foldable (DList' n) where\n    foldMap = T.foldMapDefault\n \nmkDList :: [a] -\u003e DList a\nmkDList xs =fromJust . Map.lookup 0 . tie' $ dict\n  where\n    dict = Map.fromList \n            . map (\\(i, x) -\u003e (i, DLNode' (pre i) x (nxt i)))\n            . zip [0..] $ xs\n    n = length xs\n    pre i = (i + n - 1) `rem` n\n    nxt i = (i + 1) `rem` n\n```\n\n\n# Copyright\n\nCopyright 2012, Petr Pudlák\n\nContact: [petr.pudlak.name](http://petr.pudlak.name/).\n\n![LGPLv3](https://www.gnu.org/graphics/lgplv3-88x31.png)\n\nThis program is free software: you can redistribute it and/or modify it under\nthe terms of the GNU Lesser General Public License as published by the Free\nSoftware Foundation, either version 3 of the License, or (at your option) any\nlater version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY\nWARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\nPARTICULAR PURPOSE.  See the GNU Lesser General Public License for more\ndetails.\n\nYou should have received a copy of the GNU Lesser General Public License along\nwith this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fppetr%2Ftie-knot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fppetr%2Ftie-knot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fppetr%2Ftie-knot/lists"}