{"id":37018889,"url":"https://github.com/garciat/java-type-classes","last_synced_at":"2026-01-14T02:01:08.698Z","repository":{"id":329834641,"uuid":"1115615892","full_name":"Garciat/java-type-classes","owner":"Garciat","description":"Haskell-like type class resolution for Java.","archived":false,"fork":false,"pushed_at":"2025-12-22T15:38:26.000Z","size":146,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-23T10:33:00.995Z","etag":null,"topics":["haskell","java","typeclasses"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Garciat.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-13T07:43:33.000Z","updated_at":"2025-12-22T15:38:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Garciat/java-type-classes","commit_stats":null,"previous_names":["garciat/java-type-classes"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/Garciat/java-type-classes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Garciat%2Fjava-type-classes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Garciat%2Fjava-type-classes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Garciat%2Fjava-type-classes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Garciat%2Fjava-type-classes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Garciat","download_url":"https://codeload.github.com/Garciat/java-type-classes/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Garciat%2Fjava-type-classes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408710,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["haskell","java","typeclasses"],"created_at":"2026-01-14T02:01:07.533Z","updated_at":"2026-01-14T02:01:08.642Z","avatar_url":"https://github.com/Garciat.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Type Class resolution for Java\n\n[![codecov](https://codecov.io/gh/Garciat/java-type-classes/branch/main/graph/badge.svg)](https://codecov.io/gh/Garciat/java-type-classes)\n[![Maven Central Version](https://img.shields.io/maven-central/v/com.garciat.typeclasses/java-type-classes)](https://central.sonatype.com/artifact/com.garciat.typeclasses/java-type-classes)\n\n## Background\n\nType classes are a powerful abstraction mechanism popularized by Haskell.\n\nThis library implements type class resolution for Java, allowing you to define\ntype classes and their instances (witnesses) in a modular fashion, and summon\nthem automatically at runtime.\n\nFor a tutorial-like explanation, see: https://garciat.com/posts/java-type-classes/\n\n## Installation\n\nThe library is published on Maven Central as [com.garciat.typeclasses/java-type-classes](https://central.sonatype.com/artifact/com.garciat.typeclasses/java-type-classes)\n\nFor the core resolution model:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.garciat.typeclasses\u003c/groupId\u003e\n  \u003cartifactId\u003ejava-type-classes-core\u003c/artifactId\u003e\n  \u003cversion\u003e0.1.5\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nFor some predefined type classes \u0026 instances:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.garciat.typeclasses\u003c/groupId\u003e\n  \u003cartifactId\u003ejava-type-classes-instances\u003c/artifactId\u003e\n  \u003cversion\u003e0.1.5\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nFor the annotation processor:\n\n```xml\n\u003cbuild\u003e\n  \u003cplugins\u003e\n    \u003cplugin\u003e\n      \u003cartifactId\u003emaven-compiler-plugin\u003c/artifactId\u003e\n      \u003cconfiguration\u003e\n        \u003cannotationProcessorPaths\u003e\n          \u003cpath\u003e\n            \u003cgroupId\u003ecom.garciat.typeclasses\u003c/groupId\u003e\n            \u003cartifactId\u003ejava-type-classes-core\u003c/artifactId\u003e\n            \u003cversion\u003e0.1.5\u003c/version\u003e\n          \u003c/path\u003e\n        \u003c/annotationProcessorPaths\u003e\n      \u003c/configuration\u003e\n    \u003c/plugin\u003e\n  \u003c/plugins\u003e\n\u003c/build\u003e\n```\n\n## API\n\n```java\n@interface TypeClass {\n  @interface Witness {}\n}\n\ninterface Ty\u003cT\u003e {} // witness type token\n\nclass TypeClasses {\n  static \u003cT\u003e T witness(Ty\u003cT\u003e ty);\n}\n```\n\nWhere:\n\n- For a witness type `C\u003cT1, T2, ..., Tn\u003e`, `witness()` looks for witness\n  constructors in `C` and `T1, T2, ..., Tn`.\n- Witness constructors for a type `T` are its `public static` methods annotated\n  with `@TypeClass.Witness`.\n- For a witness constructor `C\u003cT\u003e ctor(D1, D2, ..., Dn)`, the witness\n  dependencies `D1, D2, ..., Dn` are resolved recursively.\n- Resolution fails when multiple witness constructors exist for a witness type,\n  after applying overlapping instances reduction.\n- Resolution fails when a witness constructor for a witness type cannot be\n  found.\n- Witness summoning is the result of recursively invoking witness constructors\n  up their respective dependency trees.\n- `T witness(Ty\u003cT\u003e)` summons a witness of type `T` or fails with a runtime\n  exception of type `TypeClasses.WitnessResolutionException`.\n\n## Example\n\n```java\n// Type class definition\n@TypeClass\npublic interface Show\u003cT\u003e {\n  String show(T value);\n\n  // Helper for inference:\n  static \u003cT\u003e String show(Show\u003cT\u003e showT, T value) {\n    return showT.show(value);\n  }\n\n  // Witness definitions:\n\n  // \"Leaf\" witness with no dependencies:\n  @TypeClass.Witness\n  static Show\u003cInteger\u003e integerShow() {\n    return i -\u003e Integer.toString(i);\n  }\n\n  // Witness with dependencies (constraints):\n  @TypeClass.Witness\n  static \u003cA\u003e Show\u003cList\u003cA\u003e\u003e listShow(Show\u003cA\u003e showA) {\n    return listA -\u003e listA.stream().map(showA::show).collect(Collectors.joining(\", \", \"[\", \"]\"));\n  }\n}\n\n// Custom type\nrecord Pair\u003cA, B\u003e(A first, B second) {\n  @TypeClass.Witness\n  public static \u003cA, B\u003e Show\u003cPair\u003cA, B\u003e\u003e pairShow(Show\u003cA\u003e showA, Show\u003cB\u003e showB) {\n    return pair -\u003e \"(\" + showA.show(pair.first()) + \", \" + showB.show(pair.second()) + \")\";\n  }\n}\n\n// Usage\nclass Example {\n  void main() {\n    Pair\u003cInteger, List\u003cInteger\u003e\u003e value = new Pair\u003c\u003e(1, List.of(2, 3, 4));\n\n    // Summon (and use) the Show witness for Pair\u003cInteger, List\u003cInteger\u003e\u003e:\n    String s = Show.show(witness(new Ty\u003c\u003e() {}), value);\n\n    System.out.println(s); // prints: (1, [2, 3, 4])\n  }\n}\n```\n\n## Other features\n\n- Support for higher-kinded type classes like `Functor\u003cF\u003c_\u003e\u003e`, `Monad\u003cM\u003c_\u003e\u003e`, etc.\n    - See the `api.hkt` package for details.\n- Support for overlapping instances _a la_ Haskell.\n    - Based\n      on [this GHC spec](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/instances.html#overlapping-instances).\n\n## Future work\n\n- Annotation processor:\n    - To reify the witness graph at compile time.\n    - To support parameterless `witness()` calls.\n- Caching of summoned witnesses.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgarciat%2Fjava-type-classes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgarciat%2Fjava-type-classes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgarciat%2Fjava-type-classes/lists"}