{"id":16348924,"url":"https://github.com/sheaf/generic-labels","last_synced_at":"2025-11-11T15:30:12.379Z","repository":{"id":62436012,"uuid":"337229373","full_name":"sheaf/generic-labels","owner":"sheaf","description":"Labelled arguments with optional parameters in Haskell, using generic-lens","archived":false,"fork":false,"pushed_at":"2021-02-09T19:51:24.000Z","size":34,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-28T17:44:56.442Z","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sheaf.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-02-08T22:39:53.000Z","updated_at":"2024-02-19T17:16:03.000Z","dependencies_parsed_at":"2022-11-01T21:16:47.727Z","dependency_job_id":null,"html_url":"https://github.com/sheaf/generic-labels","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sheaf%2Fgeneric-labels","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sheaf%2Fgeneric-labels/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sheaf%2Fgeneric-labels/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sheaf%2Fgeneric-labels/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sheaf","download_url":"https://codeload.github.com/sheaf/generic-labels/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239593060,"owners_count":19664855,"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-11T00:55:52.203Z","updated_at":"2025-11-11T15:30:12.293Z","avatar_url":"https://github.com/sheaf.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# generic-labels \u003ca href=\"https://hackage.haskell.org/package/generic-labels\" alt=\"Hackage\"\u003e\u003cimg src=\"https://img.shields.io/hackage/v/generic-labels.svg\" /\u003e\u003c/a\u003e\n\n* [Disclaimer](#disclaimer)\n* [Introduction](#introduction)\n* [Usage](#usage)\n  - [Adapters](#adapters)\n  - [Projections](#projections)\n  - [Injections](#injections)\n* [Comparison with `generic-lens`](#comparison)\n\n\u003ca name=\"disclaimer\"\u003e\u003c/a\u003e\n# Disclaimer\n\nThis is a little experiment on a variant of [`generic-lens`](https://hackage.haskell.org/package/generic-lens)'s [structural subtyping](https://hackage.haskell.org/package/generic-lens/docs/Data-Generics-Product-Subtype.html)\nwith support for labelled types (of the form `\"label\" := ty`) in tandem with record field names.\n\nI've tried to ensure reasonable error messages and type inference, but its use should probably remain limited\nto simple situations like flat records, similarly to [`generic-lens`](https://hackage.haskell.org/package/generic-lens)'s [`Subtype`](https://hackage.haskell.org/package/generic-lens/docs/Data-Generics-Product-Subtype.html).\n\n\u003ca name=\"introduction\"\u003e\u003c/a\u003e\n# Introduction\n\nThis library performs impedance matching for collections of labelled types,\nsimilar to the [`Subtype`](https://hackage.haskell.org/package/generic-lens/docs/Data-Generics-Product-Subtype.html)\nfunctionality of [`generic-lens`](https://hackage.haskell.org/package/generic-lens).\n\nThis allows one to project out a collection of fields of a record, to plug a smaller record into a bigger one, and to\nbuild up a record out of two sub-parts.\n\nIt can also be useful to emulate very basic extensible records, as the library supports both built-in record field names\nas well as explicitly labelled types using [`OverloadedLabels`](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/overloaded_labels.html).\n\n\u003ca name=\"usage\"\u003e\u003c/a\u003e\n# Usage\n\n\u003ca name=\"adapters\"\u003e\u003c/a\u003e\n## Adapters\n\nThe main function this library exports is\n\n```haskell\nadapt :: Adapt args opt all =\u003e args -\u003e opt -\u003e all\n```\n\nHere `adapt` can be thought of as an adapter for a function which requires a certain collection of arguments,\nbut also provides default values.\n\nFor instance, consider a function which takes:\n  - two (required) `Float`s,\n  - one optional `Float` with default value `0`,\n  - one optional `Float` with default value `1`,\n  - one optional `Bool` with default value `False`.\n\nThis corresponds to the following types:\n\n```haskell\ntype AllArgs = ( \"f1\" := Float, \"f2\" := Float, \"f3\" := Float, \"f4\" := Float, \"b\" := Bool )\ntype OptArgs = ( \"f3\" := Float, \"f4\" := Float, \"b\" := Bool )\n```\n\nWe then have a function `foo :: AllArgs -\u003e res` that we might want to call on only a subset of the fields of `AllArgs`. We can define:\n\n```haskell\nadaptedFoo :: Adapt args OptArgs AllArgs =\u003e args -\u003e res\nadaptedFoo args = foo ( adapt args defaults )\n  where\n    defaults :: OptArgs\n    defaults = ( #f3 := 0, #f4 := 1, #b := False )\n```\n\nWe can then call `adaptedFoo` at any collection of fields, provided that the required arguments are present:\n\n\n```haskell\ncall1, call2, call3 :: res\ncall1 = adaptedFoo ( #f1 := 0.5, #f2 := 1.0 )\ncall2 = adaptedFoo ( #f2 := 1.0, #b := True, #f1 := 0.5 )\ncall3 = adaptedFoo ( #f1 := 0.5, #f2 := 1.0, #f3 := -1.0, #f4 := 2.0 )\n```\n\nInvalid uses will throw relevant error messages, for instance:\n\n```haskell\ncall4 :: res\ncall4 = adaptedFoo ( #f1 := 0.5, #b := True )\n```\n\n```\n  * No instance for\n        Adapt\n          (\"f1\" := Float, \"b\" := Bool)\n          (\"f3\" := Float, \"f4\" := Float, \"b\" := Bool)\n          (\"f1\" := Float, \"f2\" := Float, \"f3\" := Float, \"f4\" := Float, \"b\" := Bool)\n\n    The following types are non-optional but have not been provided:\n      - #f2 := Float\n```\n\n```haskell\ncall5 :: res\ncall5 = adaptedFoo ( #f1 := 0.5, #f2 := 1.0, #xxx := \"redundant\" )\n```\n\n```\n  * No instance for\n        Adapt\n          (\"f1\" := Float, \"f2\" := Float, \"xxx\" := [Char])\n          (\"f3\" := Float, \"f4\" := Float, \"b\" := Bool)\n          (\"f1\" := Float, \"f2\" := Float, \"f3\" := Float, \"f4\" := Float, \"b\" := Bool)\n\n    The following provided types do not appear in the destination:\n      - #xxx := [Char]\n```\n\nThese examples have used explicitly named arguments using `OverloadedLabels`, but plain records are also supported:\n\n```haskell\ndata FI = FI { float :: Float, int :: Int }\n  deriving stock Generic\n\ndata CIBF = CIBF\n  { char  :: Char\n  , int   :: Int\n  , bool  :: Bool\n  , float :: Float\n  }\n  deriving stock Generic\n\ndata BC = BC { bool :: Bool, char :: Char }\n  deriving stock Generic\n\nfi_to_cibf :: FI -\u003e CIBF\nfi_to_cibf fi = adapt fi ( BC { bool = False, char = '?' } )\n```\n\n\u003ca name=\"projections\"\u003e\u003c/a\u003e\n## Projections\n\nWe can project out a subset of fields, similarly to the [`upcast`](https://hackage.haskell.org/package/generic-lens/docs/Data-Generics-Product-Subtype.html#v:upcast)\nfunction from [`generic-lens`](https://hackage.haskell.org/package/generic-lens).\n\n```haskell\nproject :: Project big small =\u003e big -\u003e small\n```\n\nRe-using the example from the previous section, we can project out just the `\"bool\"` and `\"char\"` fields:\n\n```haskell\ncibf_to_bc :: CIBF -\u003e BC\ncibf_to_bc = project\n```\n\n\n\u003ca name=\"injections\"\u003e\u003c/a\u003e\n## Injections\n\nWe can override a subset of the fields of a record with those from a smaller record,\nsimilarly to the [`smash`](https://hackage.haskell.org/package/generic-lens/docs/Data-Generics-Product-Subtype.html#v:smash)\nfunction from [`generic-lens`](https://hackage.haskell.org/package/generic-lens):\n\n```haskell\ninject :: Inject small big =\u003e small -\u003e big -\u003e big\n```\n\nRe-using the running example:\n\n```haskell\nplug_in_bc :: BC -\u003e CIBF -\u003e CIBF\nplug_in_bc = inject\n```\n\n\u003ca name=\"comparison\"\u003e\u003c/a\u003e\n# Comparison with `generic-lens`\n\nThis library is based off [`generic-lens`](https://hackage.haskell.org/package/generic-lens), with a modification to the underlying framework\nof its [`Subtype`](https://hackage.haskell.org/package/generic-lens/docs/Data-Generics-Product-Subtype.html) typeclass in order\nto support both standard record field names as well as explicitly labelled types.\n\nThis allows us to write code like the following:\n\n```haskell\ndata IBC = IBC\n  { int  :: Int\n  , bool :: Bool\n  , char :: Char\n  }\n  deriving stock Generic\n\nibc_to_ci :: IBC -\u003e ( \"char\" := Char, \"bool\" := Bool )\nibc_to_ci = project\n```\n\nWe can thus re-use anonymous tuple types, providing a basic version of extensible records.\n\nAnother difference is that this library provides the more general function `adapt`, which allows us to\nbuild up a record out of two separate parts (useful for emulating named optional arguments).    \nThis is in contrast to the [`super`](https://hackage.haskell.org/package/generic-lens/docs/Data-Generics-Product-Subtype.html#v:super)\nlens, which only allows us to focus on a single subpart – with no notion of its complement.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsheaf%2Fgeneric-labels","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsheaf%2Fgeneric-labels","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsheaf%2Fgeneric-labels/lists"}