{"id":17524096,"url":"https://github.com/gspia/fcf-containers","last_synced_at":"2025-04-23T17:22:53.714Z","repository":{"id":62435948,"uuid":"237025411","full_name":"gspia/fcf-containers","owner":"gspia","description":"fcf-containers add tools that can be used with first-class-families","archived":false,"fork":false,"pushed_at":"2023-05-10T04:34:44.000Z","size":214,"stargazers_count":3,"open_issues_count":4,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-25T17:41:34.096Z","etag":null,"topics":["dependent-types","haskell","haskell-library","types"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gspia.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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":"2020-01-29T16:10:12.000Z","updated_at":"2023-05-22T07:01:32.000Z","dependencies_parsed_at":"2025-03-06T04:32:37.306Z","dependency_job_id":"43925709-3d83-446a-8cc6-e34848ede90a","html_url":"https://github.com/gspia/fcf-containers","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gspia%2Ffcf-containers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gspia%2Ffcf-containers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gspia%2Ffcf-containers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gspia%2Ffcf-containers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gspia","download_url":"https://codeload.github.com/gspia/fcf-containers/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250478173,"owners_count":21437116,"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":["dependent-types","haskell","haskell-library","types"],"created_at":"2024-10-20T14:06:27.051Z","updated_at":"2025-04-23T17:22:53.679Z","avatar_url":"https://github.com/gspia.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fcf-containers [![Hackage](https://img.shields.io/hackage/v/fcf-containers.svg)](https://hackage.haskell.org/package/fcf-containers) [![Build Status](https://travis-ci.org/gspia/fcf-containers.svg)](https://travis-ci.org/gspia/fcf-containers)\n\nFcf-containers mimicks the containers package but for type-level computations. \nThat is, we provide e.g. trees and maps. In addition to that, this package \ncontains some other type-level computation utilities. \n\nThese methods are based on the idea given in the\n[first-class-families](https://github.com/Lysxia/first-class-families) -package,\nor Fcf shortly. Fcf is the main dependency of fcf-containers. As some of the\nmethods fit badly under the name \"fcf-containers\", they might end up into \nthe Fcf or some other package to be created. So stay tuned, be patient, check \nthe [TODO.md](https://github.com/gspia/fcf-containers/blob/master/TODO.md) \nand send those PR's :)\n\n\nMotivation for calculating things on type-level or on compile-time \ninclude\n\n- increase the safety measures of runtime methods,\n- pre-calculate complex things once on compile time and not every time the\n  executable is run, \n- provide users a way to choose between different algorithms for solving\n  a problem based on problem instance properties (e.g. local vs network,\n  or small vs large) known in advance.\n \nWhy fcf-like? The kind of signatures used for functions might be easier to \nread for some people and the ability to apply partially a function is nice \ntool to have. The techniques that allows this are defunctionalization, \nencoding the functions with empty data types and the use of open type family \nto Eval the constructed expressions. \n \nIf you have other motivations, please do let us know! \n\nNote: some of the claims on the items in the above list are such that I \nbelieve/hope but really don't know at the moment nor do I know how check them. \nE.g. the matter of compile time vs run time. Yes, types are erased at compile \ntime but do they still leave something into executables: simple check by \ncomparing outputs of the orbit example and another program that has one method \nto print integer 42 and main, reveals that sizes are almost the same, but not \nexactly.\n\n\nThere are lot of open interesting questions. See \n[TODO.md](https://github.com/gspia/fcf-containers/blob/master/TODO.md) file. E.g. how combine \nthese techniques with singletons-lib and related techniques. \n\n\n\n## Installation and building \n\nFirst, get the repo with `git clone` and `cd` into the directory. \n\n```\nnix-shell \ncabal build \ncabal test \n```\n\nIf you are flakes user, `nix develop -c zsh` (or without that `-c zsh`) works as well.\n\nThe doc-tests both document and work partly as testing mechanism for this lib. Please \ndo note that we are moving away from the doc-tests and building the testing modules \nunder `test` directory.\n\nIf you don't use nix, `cabal install fcf-containers` should be enough. This\npackage has almost as good number of dependencies as the first-class-families.\n\n\n## Example\n\n\n### Test cases as examples\n\nThe  \n[test directory](https://github.com/gspia/fcf-containers/blob/master/test)\ncontains a lot of useful examples.  There you will find out, how to apply most\nof the methods: examples that only work on \"compile time\", and examples on how\nto get the results from type level calculations to value level (see the Reflect\ntest module and the `fromType` method applications, also in some other testing\nmodules).\n\n\n### Three example programs calculating something\n\nThese are a bit larger examples, but not yet too large: somewhat convenient small \nmodule size.  Idea was to take an algorithm, and convert it to a type-level \ncomputation, or in some other way give an example of methods that this library\nprovides.\n\n\nSee [Orbits.hs](https://github.com/gspia/fcf-containers/blob/master/examples/Orbits.hs). \nIt shows how to solve a real problem,\nwhat PRAGMAs are probably needed etc.\n\n```\ncabal run orbits \n```\n\nThere is also another Advent of Code problem, see the Carbcombat file.\n\n\nTo see, how to use MapC, take a look at\n[Haiku.hs](https://github.com/gspia/fcf-containers/blob/master/examples/Haiku.hs)\n\n```\ncabal run haiku \n```\n\n\n### Other example material\n\nPlease, do take a look of the notes made for the Helsinki Haskell meetup\non 11th January 2023\n[notes](https://github.com/gspia/fcf-containers/blob/master/examples/20230111_hhslides.md)\nand the associated \n[code examples](https://github.com/gspia/fcf-containers/blob/master/examples/20230111_hhmeetup.hs).\n\n\n\n## Random Notes\n\n### Partiality and anonymous functions\n\nIn the end, everything has to be total. We just post-pone the totality checking\nwith defunctionalization in a way by trying to evaluate our functions as late\nas possible with the `Eval` function. \n\nWe don't have lambdas, but if you can write the helper function in point-free\nform, it might can be used directly without any global function definition.\nRemember, that `(\u003c=\u003c)` corresponds to term-level `(.)` and `(=\u003c\u003c)` to \nterm-level function application `($)`. See also Maguire's book \n(Thinking with Types).\n\n\n### Conflicting family instance declarations\n\nTransforming term-level Haskell code is relatively straigthforward. Often, \nlocal definitions in `where` and anonymous functions will be turned into \nseparate helper functions. \n\nOccasionally, the pattern matching is not quite enough. Please, consider\n\n```\nisPrefixOf              :: (Eq a) =\u003e [a] -\u003e [a] -\u003e Bool\nisPrefixOf [] _         =  True\nisPrefixOf _  []        =  False\nisPrefixOf (x:xs) (y:ys)=  x == y \u0026\u0026 isPrefixOf xs ys\n```\n\nWe could try to define it as \n```\ndata IsPrefixOf :: [a] -\u003e [a] -\u003e Exp Bool\ntype instance Eval (IsPrefixOf '[] _) = 'True\ntype instance Eval (IsPrefixOf _ '[]) = 'False\ntype instance Eval (IsPrefixOf (x ': xs) (y ': ys)) =\n         Eval ((Eval (TyEq x y)) \u0026\u0026 Eval (IsPrefixOf xs ys))\n```\n\nBut ghc does not like this definition: the first two type instances are\nconflicting together. Instead, in these situations we can use a helper type \nfamily:\n\n```\ndata IsPrefixOf :: [a] -\u003e [a] -\u003e Exp Bool\ntype instance Eval (IsPrefixOf xs ys) = IsPrefixOf_ xs ys\n\n-- helper for IsPrefixOf\ntype family IsPrefixOf_ (xs :: [a]) (ys :: [a]) :: Bool where\n    IsPrefixOf_ '[] _ = 'True\n    IsPrefixOf_ _ '[] = 'False\n    IsPrefixOf_ (x ': xs) (y ': ys) =\n         Eval ((Eval (TyEq x y)) \u0026\u0026 IsPrefixOf_ xs ys)\n```\n\n### Using `If`\n\nIf possible, try to avoid using `Eval` in the if-branches. \nFor example, consider\n```\n    (If (Eval (s \u003e 0) )\n        ( 'Just '( a, s TL.- 1 ))\n        'Nothing\n    )\n```\nand\n```\n    (If (Eval (s \u003e 0))\n        (Eval (Pure ( 'Just '( a, s TL.- 1 ))))\n        (Eval (Pure 'Nothing))\n    )\n```\n\nBoth compile and it is easy to end up in the latter form, especially if the \nbranch is more complex than in this example. \n\nThe former, however, is much better as it doesn't have to evaluate both branches\nand is thus more efficient.\n\n\n### Other\n\n\nThe `ghci` and `:kind!` command are your friends!\n\nSource also contains a lot of examples, see\n[fcf-containers](https://github.com/gspia/fcf-containers/tree/master/src/Fcf).\nThe examples will be left near the code, even thou the doctest runs will be \nremoved and replaced with real tests at the test-directory.\n\nHappy :kinding!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgspia%2Ffcf-containers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgspia%2Ffcf-containers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgspia%2Ffcf-containers/lists"}