{"id":42842108,"url":"https://github.com/palatable/shoki","last_synced_at":"2026-01-30T11:52:22.598Z","repository":{"id":57725633,"uuid":"98058125","full_name":"palatable/shoki","owner":"palatable","description":"Purely functional data structures in Java","archived":false,"fork":false,"pushed_at":"2021-05-14T18:24:24.000Z","size":657,"stargazers_count":39,"open_issues_count":12,"forks_count":11,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-08-05T07:06:39.365Z","etag":null,"topics":["data-structures","hamt","hash-array-mapped-trie","hashmap","hashset","immutable","immutable-datastructures","java","multiset","okasaki","persistent-data-structure","purely-functional-data-structures","purelyfunctionaldatastructures","queue","stack"],"latest_commit_sha":null,"homepage":"https://palatable.github.io/shoki/","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/palatable.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}},"created_at":"2017-07-22T21:12:36.000Z","updated_at":"2025-01-14T06:14:16.000Z","dependencies_parsed_at":"2022-09-02T03:40:56.322Z","dependency_job_id":null,"html_url":"https://github.com/palatable/shoki","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/palatable/shoki","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palatable%2Fshoki","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palatable%2Fshoki/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palatable%2Fshoki/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palatable%2Fshoki/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/palatable","download_url":"https://codeload.github.com/palatable/shoki/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palatable%2Fshoki/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28912098,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T08:15:08.179Z","status":"ssl_error","status_checked_at":"2026-01-30T08:14:31.507Z","response_time":66,"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":["data-structures","hamt","hash-array-mapped-trie","hashmap","hashset","immutable","immutable-datastructures","java","multiset","okasaki","persistent-data-structure","purely-functional-data-structures","purelyfunctionaldatastructures","queue","stack"],"created_at":"2026-01-30T11:52:21.781Z","updated_at":"2026-01-30T11:52:22.590Z","avatar_url":"https://github.com/palatable.png","language":"Java","readme":"Shōki (正気)\n======\n[![Build Status](https://travis-ci.com/palatable/shoki.svg?branch=master)](https://travis-ci.com/github/palatable/shoki)\n[![Shōki](https://img.shields.io/maven-central/v/com.jnape.palatable/shoki.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.shoki)\n[![Shōki](https://img.shields.io/maven-metadata/v?color=aaa\u0026label=development\u0026metadataUrl=https%3A%2F%2Foss.sonatype.org%2Fcontent%2Frepositories%2Fsnapshots%2Fcom%2Fjnape%2Fpalatable%2Fshoki%2Fmaven-metadata.xml)](https://oss.sonatype.org/content/repositories/snapshots/com/jnape/palatable/shoki/)\n\nPurely functional, persistent data structures for the JVM.\n\n#### Table of Contents\n\n - [Background](#background)\n - [Installation](#installation)\n - [Hierarchy](#hierarchy)\n - [Implementations](#implementations)\n   - [`StrictStack\u003cA\u003e`](#implementations-StrictStack)\n   - [`StrictQueue\u003cA\u003e`](#implementations-StrictQueue)\n   - [`HashMap\u003cK, V\u003e`](#implementations-HashMap)\n   - [`HashSet\u003cA\u003e`](#implementations-HashSet)\n   - [`HashMultiSet\u003cA\u003e`](#implementations-HashMultiSet)\n   - [`TreeMap\u003cK, V\u003e`](#implementations-TreeMap)\n   - [`TreeSet\u003cA\u003e`](#implementations-TreeSet)\n   - [`TreeMultiSet\u003cA\u003e`](#implementations-TreeMultiSet)\n - [License](#license)\n\n\u003ca name=\"background\"\u003eBackground\u003c/a\u003e\n----------\n\n_Shōki_ is a library offering purely functional, persistent data structures for the JVM. \n\nSo why another data structures library? Because writing correct code is hard, and it's especially hard if your data\nstructures consistently advertise false interfaces. The data structures provided by _Shōki_ are built on top of\ninterfaces that promote type-checker participation by leveraging rich types, and encourage correct-by-construction\nsoftware with obvious usage semantics.\n\nStandard usage of Shōki interfaces should never throw: there are no `IndexOutOfBoundsException`s that result from\nseemingly innocuous `get` calls; no `UnsupportedOperationException`s because the interface you're presented with is an\n_absolute fiction_, and somewhere under the covers is an immutable collection masquerading as a mutable one; no\n`ClassCastExceptions` because a data structure that fundamentally only works in the presence of comparability fails \nto enforce this essential constraint at compile time. Any of these things happening is considered an error in _Shōki_,\nnot in user code.\n\nThe constraints of the inputs and the outputs are also richly specified via their type signatures. If a lookup cannot\nbe guaranteed to yield a value, it will return a\n[`Maybe`](https://github.com/palatable/lambda/blob/master/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java)\nrather than `null` so the type-checker can remind you that you may not have received what you wanted. If a value\nfundamentally cannot be zero, it will very likely be represented by a type that does not even include a \"zero\" term, so\nyou don't waste mental energy writing code to handle impossible scenarios. If the total size of a collection can\nlogically exceed `Integer.MAX_VALUE`, its `sizeInfo` will advertise a type that can realistically represent its size\ninstead of one that might represent a negative value due to overflow.\n\nThe target audience for _Shōki_ considers these characteristics not to be fine luxuries, but rather basic\nquality-of-life essentials. If you think your time is too valuable to be spent staring at four methods with four\nidentical type signatures, trying to remember whether `peek` or `poll` throws or returns `null`, or `element` or\n`remove` alters its underlying structure or doesn't; then you're in good company. Welcome!\n\n\u003ca name=\"installation\"\u003eInstallation\u003c/a\u003e\n------------\n\n_Shōki_ alpha releases are currently available in Maven Central. These alpha releases are meant to be of high enough\nquality as to be reliable in a production environment, while still allowing significant API changes to occur before a\n`1.0` release. \n\nAdd the following dependency to your:\n\n`pom.xml` ([Maven](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)):\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.jnape.palatable\u003c/groupId\u003e\n    \u003cartifactId\u003eshoki\u003c/artifactId\u003e\n    \u003cversion\u003e1.0-alpha-2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n`build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)):\n\n```gradle\ncompile group: 'com.jnape.palatable', name: 'shoki', version: '1.0-alpha-2'\n```\n\n\u003ca name=\"hierarchy\"\u003eHierarchy\u003c/a\u003e\n------------\n\nOne of the core design tenants of _Shōki_'s API is that a data structure is modeled as the incremental composition of\nits orthogonal capabilities and constraints.\n\n#### Top-level orthogonal building blocks\n\n- `Sequence\u003cA\u003e`: an `Iterable\u003cA\u003e` interface that offers the methods `Maybe\u003cA\u003e head()` and `Sequence\u003cA\u003e tail()`\n- `SizeInfo`: a coproduct of `Unknown` or `Known\u003cN extends Number\u003e`, where `Known\u003cN\u003e` offers a method `N getSize()`\n- `Sizable`: an interface that offers a method `SizeInfo sizeInfo()`\n- `Membership\u003cA\u003e`: an interface that offers a membership test method `boolean contains(A)`     \n- `RandomAccess\u003cIndex, V\u003e`: `Membership\u003cIndex\u003e` with an additional lookup method `V get(Index)`     \n- `Natural`: a `Number` sum type of `Zero` or `NonZero` that never overflows and offers basic type-safe arithmetic       \n\n#### Refined data structure interfaces\n\n- `Collection\u003cSize extends Number, A\u003e`: a `Sequence\u003cA\u003e` that supports `SizeInfo` yielding a `Known\u003cSize\u003e`\n- `OrderedCollection\u003cSize extends Number, A\u003e`: a `Collection\u003cSize, A\u003e` that offers a `reverse()` method\n- `SortedCollection\u003cSize extends Number, A, Ordering\u003e`: an `OrderedCollection\u003cSize, A\u003e` that offers `Maybe\u003cA\u003e min()`,\n  `Maybe\u003cA\u003e max`, and `SortedCollection\u003cSize, A, Ordering\u003e sort(Comparator\u003c? super Ordering\u003e comparator)` methods\n- `Stack\u003cSize extends Number, A\u003e`: an `OrderedCollection\u003cSize, A\u003e` with a method `Stack\u003cSize, A\u003e cons(A)` that adds an\n  element to the top of the `Stack\u003cSize, A\u003e`  \n- `Queue\u003cSize extends Number, A\u003e`: an `OrderedCollection\u003cSize, A\u003e` with a method `Queue\u003cSize, A\u003e snoc(A)` that adds an\n  element to the bottom of the `Queue\u003cSize, A\u003e`   \n- `Set\u003cSize extends Number, A\u003e`: a `Collection\u003cSize, A\u003e` that supports `Membership\u003cA\u003e`\n- `MultiSet\u003cA\u003e`: a `Collection\u003cNatural, A\u003e` of `Tuple2\u003cA, Natural.NonZero\u003e` that supports `RandomAccess\u003cA, Natural\u003e`\n- `Map\u003cSize extends Number, K, V\u003e`: a `Collection\u003cSize, Tuple2\u003cK, V\u003e\u003e` that supports `RandomAccess\u003cK, Maybe\u003cV\u003e\u003e`\n\n_Shōki_ is still very much in alpha development, so these specific interfaces are subject to change, but they should at\nleast offer an intuition about the way in which the design is being approached. \n\n\u003ca name=\"implementations\"\u003eImplementations\u003c/a\u003e\n------------\n\n#### \u003ca name=\"implementations-StrictStack\"\u003e`StrictStack\u003cA\u003e`\u003c/a\u003e\n\nA `StrictStack\u003cA\u003e` is a strictly-evaluated `Stack\u003cNatural, A\u003e` that offers worst-case `O(1)` space/time for `cons`,\n`head`, and `tail`.  \n\n```java\nimport com.jnape.palatable.lambda.adt.Maybe;\nimport com.jnape.palatable.shoki.impl.StrictStack;\n\nimport static com.jnape.palatable.shoki.impl.StrictStack.strictStack;\n\npublic class Example {\n\n    public static void main(String[] args) {\n        StrictStack\u003cString\u003e empty     = strictStack();\n        boolean             _true     = empty.isEmpty();\n        Maybe\u003cString\u003e       nothing   = empty.head();\n        StrictStack\u003cString\u003e alsoEmpty = empty.tail();\n\n        StrictStack\u003cString\u003e fooBarBaz = empty.cons(\"baz\").cons(\"bar\").cons(\"foo\");\n        boolean             _false    = fooBarBaz.isEmpty();\n        Maybe\u003cString\u003e       justFoo   = fooBarBaz.head();\n\n        StrictStack\u003cString\u003e barBaz  = fooBarBaz.tail();\n        Maybe\u003cString\u003e       justBar = barBaz.head();\n\n        StrictStack\u003cString\u003e baz     = barBaz.tail();\n        Maybe\u003cString\u003e       justBaz = baz.head();\n\n        StrictStack\u003cString\u003e bazBarFooBaz = baz.consAll(fooBarBaz);\n        boolean             __true       = bazBarFooBaz.equals(strictStack(\"baz\", \"bar\", \"foo\", \"baz\"));\n    }\n}\n```\n\n#### \u003ca name=\"implementations-StrictQueue\"\u003e`StrictQueue\u003cA\u003e`\u003c/a\u003e\n\nA `StrictQueue\u003cA\u003e` is a strictly-evaluated `Queue\u003cNatural, A\u003e` and `Stack\u003cNatural, A\u003e` that offers worst-case `O(1)`\nspace/time for `cons`, `snoc`, and `head`, and amortized `O(1)` for `tail`.\n\n```java\nimport com.jnape.palatable.lambda.adt.Maybe;\nimport com.jnape.palatable.shoki.impl.StrictQueue;\n\nimport static com.jnape.palatable.shoki.impl.StrictQueue.strictQueue;\n\npublic class Example {\n\n    public static void main(String[] args) {\n        StrictQueue\u003cString\u003e empty     = strictQueue();\n        boolean             _true     = empty.isEmpty();\n        Maybe\u003cString\u003e       nothing   = empty.head();\n        StrictQueue\u003cString\u003e alsoEmpty = empty.tail();\n\n        StrictQueue\u003cString\u003e fooBarBaz     = empty.snoc(\"foo\").snoc(\"bar\").snoc(\"baz\");\n        boolean             _false        = fooBarBaz.isEmpty();\n        Maybe\u003cString\u003e       justFoo       = fooBarBaz.head();\n        StrictQueue\u003cString\u003e alsoFooBarBaz = empty.cons(\"baz\").cons(\"bar\").cons(\"foo\");\n\n        StrictQueue\u003cString\u003e barBaz  = fooBarBaz.tail();\n        Maybe\u003cString\u003e       justBar = barBaz.head();\n\n        StrictQueue\u003cString\u003e baz     = barBaz.tail();\n        Maybe\u003cString\u003e       justBaz = baz.head();\n\n        StrictQueue\u003cString\u003e bazFooBarBaz = baz.snocAll(fooBarBaz);\n        StrictQueue\u003cString\u003e bazBarFooBaz = baz.consAll(fooBarBaz);\n        boolean             __true       = bazFooBarBaz.equals(strictQueue(\"baz\", \"foo\", \"bar\", \"baz\"));\n    }\n}\n```\n\n#### \u003ca name=\"implementations-HashMap\"\u003e`HashMap\u003cK, V\u003e`\u003c/a\u003e\n\nA `HashMap\u003cK, V\u003e` is an [ideal hash tree](https://lampwww.epfl.ch/papers/idealhashtrees.pdf) implementation of a\n`Map\u003cNatural, K, V\u003e` that offers amortized `O(1)` space/time for `get`, `put`, `remove`, and `contains`, and supports\ncustom `EquivalenceRelation\u003cK\u003e`s and `HashingAlgorithm\u003cK\u003e`s.   \n\n```java\nimport com.jnape.palatable.lambda.adt.Maybe;\nimport com.jnape.palatable.lambda.adt.hlist.Tuple2;\nimport com.jnape.palatable.shoki.impl.HashMap;\nimport com.jnape.palatable.shoki.impl.HashSet;\nimport com.jnape.palatable.shoki.impl.StrictQueue;\n\nimport static com.jnape.palatable.shoki.api.EquivalenceRelation.objectEquals;\nimport static com.jnape.palatable.shoki.api.HashingAlgorithm.objectHashCode;\nimport static com.jnape.palatable.shoki.impl.HashMap.hashMap;\n\npublic class Example {\n\n    public static void main(String[] args) {\n        // same as hashMap()\n        HashMap\u003cInteger, String\u003e empty = hashMap(objectEquals(), objectHashCode());\n\n        boolean                        _true     = empty.isEmpty();\n        Maybe\u003cTuple2\u003cInteger, String\u003e\u003e nothing   = empty.head();\n        HashMap\u003cInteger, String\u003e       alsoEmpty = empty.tail();\n\n        HashMap\u003cInteger, String\u003e       fooBarBaz     = empty.put(0, \"foo\").put(1, \"bar\").put(2, \"baz\");\n        boolean                        _false        = fooBarBaz.isEmpty();\n        Maybe\u003cTuple2\u003cInteger, String\u003e\u003e just0Foo      = fooBarBaz.head();\n        HashMap\u003cInteger, String\u003e       alsoFooBarBaz = empty.put(2, \"baz\").put(1, \"bar\").put(0, \"foo\");\n        boolean                        __true        = fooBarBaz.contains(0);\n        boolean                        __false       = fooBarBaz.contains(-1);\n\n        // This HashSet uses the same EquivalenceRelation and HashingAlgorithm\n        HashSet\u003cInteger\u003e keys = fooBarBaz.keys(); // HashSet[0, 1, 2]\n\n        StrictQueue\u003cString\u003e values = fooBarBaz.values(); // StrictQueue[\"foo\", \"bar\", \"baz\"]\n\n        HashMap\u003cInteger, String\u003e       barBaz   = fooBarBaz.tail();\n        Maybe\u003cTuple2\u003cInteger, String\u003e\u003e just1Bar = barBaz.head();\n\n        HashMap\u003cInteger, String\u003e       baz      = barBaz.tail();\n        Maybe\u003cTuple2\u003cInteger, String\u003e\u003e just2Baz = baz.head();\n\n        // HashMap[(2=bazbaz)]\n        HashMap\u003cInteger, String\u003e _2bazbaz = baz.merge(baz, (s1, s2) -\u003e s1 + s2);\n    }\n}\n```\n\n#### \u003ca name=\"implementations-HashSet\"\u003e`HashSet\u003cA\u003e`\u003c/a\u003e\n\nA `HashSet\u003cA\u003e` is a `Set\u003cNatural, A\u003e` that is backed by a `HashMap\u003cA, Unit\u003e` and offers similar space/time\ncomplexities. Like `HashMap`, a `HashSet` supports custom `EquivalenceRelation\u003cK\u003e`s and `HashingAlgorithm\u003cK\u003e`s.\n\n```java\nimport com.jnape.palatable.lambda.adt.Maybe;\nimport com.jnape.palatable.shoki.impl.HashSet;\n\nimport static com.jnape.palatable.shoki.api.EquivalenceRelation.objectEquals;\nimport static com.jnape.palatable.shoki.api.HashingAlgorithm.objectHashCode;\nimport static com.jnape.palatable.shoki.impl.HashSet.hashSet;\n\npublic class Example {\n\n    public static void main(String[] args) {\n        // same as hashSet()\n        HashSet\u003cInteger\u003e empty = hashSet(objectEquals(), objectHashCode());\n\n        boolean          _true     = empty.isEmpty();\n        Maybe\u003cInteger\u003e   nothing   = empty.head();\n        HashSet\u003cInteger\u003e alsoEmpty = empty.tail();\n\n        HashSet\u003cInteger\u003e _012    = empty.add(0).add(1).add(2);\n        boolean          _false  = _012.isEmpty();\n        Maybe\u003cInteger\u003e   just0   = _012.head();\n        HashSet\u003cInteger\u003e also012 = empty.add(2).add(1).add(0);\n        boolean          __true  = _012.contains(0);\n        boolean          __false = _012.contains(-1);\n\n        HashSet\u003cInteger\u003e _12   = _012.tail();\n        Maybe\u003cInteger\u003e   just1 = _12.head();\n\n        HashSet\u003cInteger\u003e _2    = _12.tail();\n        Maybe\u003cInteger\u003e   just2 = _2.head();\n\n        HashSet\u003cInteger\u003e _01234 = _012.union(hashSet(2, 3, 4));\n        HashSet\u003cInteger\u003e _01    = _012.difference(hashSet(2, 3, 4));\n        HashSet\u003cInteger\u003e _0134  = _012.symmetricDifference(hashSet(2, 3, 4));\n        HashSet\u003cInteger\u003e __2    = _012.intersection(hashSet(2, 3, 4));\n    }\n}\n```\n\n#### \u003ca name=\"implementations-HashMultiSet\"\u003e`HashMultiSet\u003cA\u003e`\u003c/a\u003e\n\nA `HashMultiSet\u003cA\u003e` is a `MultiSet\u003cA\u003e` that is backed by a `HashMap\u003cA, Natural.NonZero\u003e` and offers similar space/time\ncomplexities. Like `HashMap`, a `HashMultiSet` supports custom `EquivalenceRelation\u003cK\u003e`s and `HashingAlgorithm\u003cK\u003e`s.\n\n```java\nimport com.jnape.palatable.lambda.adt.Maybe;\nimport com.jnape.palatable.lambda.adt.hlist.Tuple2;\nimport com.jnape.palatable.shoki.api.Natural;\nimport com.jnape.palatable.shoki.api.Natural.NonZero;\nimport com.jnape.palatable.shoki.impl.HashMultiSet;\nimport com.jnape.palatable.shoki.impl.HashSet;\n\nimport static com.jnape.palatable.shoki.api.EquivalenceRelation.objectEquals;\nimport static com.jnape.palatable.shoki.api.HashingAlgorithm.objectHashCode;\nimport static com.jnape.palatable.shoki.impl.HashMultiSet.hashMultiSet;\n\npublic class Example {\n\n    public static void main(String[] args) {\n        // same as hashMultiSet()\n        HashMultiSet\u003cInteger\u003e empty = hashMultiSet(objectEquals(), objectHashCode());\n\n        boolean                         _true     = empty.isEmpty();\n        Maybe\u003cTuple2\u003cInteger, NonZero\u003e\u003e nothing   = empty.head();\n        HashMultiSet\u003cInteger\u003e           alsoEmpty = empty.tail();\n\n        HashMultiSet\u003cInteger\u003e           _0x1_1x2_2x1     = empty.inc(0).inc(1).inc(2).inc(1);\n        boolean                         _false           = _0x1_1x2_2x1.isEmpty();\n        Maybe\u003cTuple2\u003cInteger, NonZero\u003e\u003e just0x1          = _0x1_1x2_2x1.head();\n        HashMultiSet\u003cInteger\u003e           also_0x1_1x2_2x1 = empty.inc(1).inc(2).inc(1).inc(0);\n        boolean                         __true           = _0x1_1x2_2x1.contains(0);\n        boolean                         __false          = _0x1_1x2_2x1.contains(-1);\n\n        Natural one = _0x1_1x2_2x1.get(0);\n        Natural two = _0x1_1x2_2x1.get(1);\n\n        HashMultiSet\u003cInteger\u003e           _1x2_2x1 = _0x1_1x2_2x1.tail();\n        Maybe\u003cTuple2\u003cInteger, NonZero\u003e\u003e just_1x2 = _1x2_2x1.head();\n\n        HashMultiSet\u003cInteger\u003e           _2x1     = _1x2_2x1.tail();\n        Maybe\u003cTuple2\u003cInteger, NonZero\u003e\u003e just_2x1 = _2x1.head();\n\n        HashMultiSet\u003cInteger\u003e _2x1_3x1_4x1         = hashMultiSet(2, 3, 4);\n        HashMultiSet\u003cInteger\u003e _0x1_1x2_2x1_3x1_4x1 = _0x1_1x2_2x1.union(_2x1_3x1_4x1);\n        HashMultiSet\u003cInteger\u003e _0x1_1x2             = _0x1_1x2_2x1.difference(_2x1_3x1_4x1);\n        HashMultiSet\u003cInteger\u003e _0x1_1x2_3x1_4x1     = _0x1_1x2_2x1.symmetricDifference(_2x1_3x1_4x1);\n        HashMultiSet\u003cInteger\u003e __2x1                = _0x1_1x2_2x1.intersection(_2x1_3x1_4x1);\n        HashMultiSet\u003cInteger\u003e _0x1_1x2_2x2_3x1_4x1 = _0x1_1x2_2x1.sum(_2x1_3x1_4x1);\n\n        HashSet\u003cInteger\u003e _012 = _0x1_1x2_2x1.unique();\n    }\n}\n```\n\n#### \u003ca name=\"implementations-TreeMap\"\u003e`TreeMap\u003cK, V\u003e`\u003c/a\u003e\n\nA `TreeMap\u003cK, V\u003e` is a [red-black tree](https://www.cs.tufts.edu/~nr/cs257/archive/chris-okasaki/redblack99.pdf)\nimplementation of a `Map\u003cNatural, K, V\u003e` that is also a `SortedCollection\u003cNatural, Tuple2\u003cK, V\u003e, K\u003e` offering amortized\n`O(log(n))` space/time for `get`, `put`, `remove`, and `contains`, and supports custom `Comparator\u003cK\u003e`s.\n\n```java\nimport com.jnape.palatable.lambda.adt.Maybe;\nimport com.jnape.palatable.lambda.adt.hlist.Tuple2;\nimport com.jnape.palatable.shoki.impl.StrictQueue;\nimport com.jnape.palatable.shoki.impl.TreeMap;\nimport com.jnape.palatable.shoki.impl.TreeSet;\n\nimport static com.jnape.palatable.shoki.impl.TreeMap.treeMap;\nimport static java.util.Comparator.naturalOrder;\n\npublic class Example {\n\n    public static void main(String[] args) {\n        // same as treeMap()\n        TreeMap\u003cInteger, String\u003e empty = treeMap(naturalOrder());\n\n        boolean                        _true     = empty.isEmpty();\n        Maybe\u003cTuple2\u003cInteger, String\u003e\u003e nothing   = empty.head();\n        TreeMap\u003cInteger, String\u003e       alsoEmpty = empty.tail();\n\n        TreeMap\u003cInteger, String\u003e       fooBarBaz     = empty.put(0, \"foo\").put(1, \"bar\").put(2, \"baz\");\n        boolean                        _false        = fooBarBaz.isEmpty();\n        Maybe\u003cTuple2\u003cInteger, String\u003e\u003e just0Foo      = fooBarBaz.head();\n        Maybe\u003cTuple2\u003cInteger, String\u003e\u003e alsoJust0Foo  = fooBarBaz.min();\n        Maybe\u003cTuple2\u003cInteger, String\u003e\u003e just2Baz      = fooBarBaz.max();\n        TreeMap\u003cInteger, String\u003e       alsoFooBarBaz = empty.put(2, \"baz\").put(1, \"bar\").put(0, \"foo\");\n        boolean                        __true        = fooBarBaz.contains(0);\n        boolean                        __false       = fooBarBaz.contains(-1);\n\n        // This TreeSet uses the same Comparator\n        TreeSet\u003cInteger\u003e keys = fooBarBaz.keys(); // TreeSet[0, 1, 2]\n\n        StrictQueue\u003cString\u003e values = fooBarBaz.values(); // StrictQueue[\"foo\", \"bar\", \"baz\"]\n\n        TreeMap\u003cInteger, String\u003e       barBaz   = fooBarBaz.tail();\n        Maybe\u003cTuple2\u003cInteger, String\u003e\u003e just1Bar = barBaz.head();\n\n        TreeMap\u003cInteger, String\u003e       baz          = barBaz.tail();\n        Maybe\u003cTuple2\u003cInteger, String\u003e\u003e alsoJust2Baz = baz.head();\n\n        // TreeMap[(2=bazbaz)]\n        TreeMap\u003cInteger, String\u003e _2bazbaz = baz.merge(baz, (s1, s2) -\u003e s1 + s2);\n    }\n}\n```\n\n#### \u003ca name=\"implementations-TreeSet\"\u003e`TreeSet\u003cA\u003e`\u003c/a\u003e\n\nA `TreeSet\u003cA\u003e` is a `Set\u003cNatural, A\u003e` that is also a `SortedCollection\u003cNatural, A\u003e` and is backed by a\n`TreeMap\u003cA, Unit\u003e`, offering similar space/time complexities. Like `TreeMap`, a `TreeSet` supports custom\n`Comparator\u003cK\u003e`s.\n\n```java\nimport com.jnape.palatable.lambda.adt.Maybe;\nimport com.jnape.palatable.shoki.impl.TreeSet;\n\nimport static com.jnape.palatable.shoki.impl.TreeSet.treeSet;\nimport static java.util.Comparator.naturalOrder;\n\npublic class Example {\n\n    public static void main(String[] args) {\n        // same as treeSet()\n        TreeSet\u003cInteger\u003e empty = treeSet(naturalOrder());\n\n        boolean          _true     = empty.isEmpty();\n        Maybe\u003cInteger\u003e   nothing   = empty.head();\n        TreeSet\u003cInteger\u003e alsoEmpty = empty.tail();\n\n        TreeSet\u003cInteger\u003e _012      = empty.add(0).add(1).add(2);\n        boolean          _false    = _012.isEmpty();\n        Maybe\u003cInteger\u003e   just0     = _012.head();\n        Maybe\u003cInteger\u003e   alsoJust0 = _012.min();\n        Maybe\u003cInteger\u003e   just2     = _012.max();\n        TreeSet\u003cInteger\u003e also012   = empty.add(2).add(1).add(0);\n        boolean          __true    = _012.contains(0);\n        boolean          __false   = _012.contains(-1);\n\n        TreeSet\u003cInteger\u003e _12   = _012.tail();\n        Maybe\u003cInteger\u003e   just1 = _12.head();\n\n        TreeSet\u003cInteger\u003e _2        = _12.tail();\n        Maybe\u003cInteger\u003e   alsoJust2 = _2.head();\n\n        TreeSet\u003cInteger\u003e _01234 = _012.union(treeSet(2, 3, 4));\n        TreeSet\u003cInteger\u003e _01    = _012.difference(treeSet(2, 3, 4));\n        TreeSet\u003cInteger\u003e _0134  = _012.symmetricDifference(treeSet(2, 3, 4));\n        TreeSet\u003cInteger\u003e __2    = _012.intersection(treeSet(2, 3, 4));\n    }\n}\n```\n\n#### \u003ca name=\"implementations-TreeMultiSet\"\u003e`TreeMultiSet\u003cA\u003e`\u003c/a\u003e\n\nA `TreeMultiSet\u003cA\u003e` is a `MultiSet\u003cA\u003e` that is also a `SortedCollection\u003cNatural, Tuple2\u003cA, NonZero\u003e, A\u003e`, and is backed\nby a `TreeMap\u003cA, Natural.NonZero\u003e`, offering similar space/time complexities. Like `TreeMap`, a `TreeMultiSet` supports\ncustom `Comparator\u003cK\u003e`s.\n\n```java\nimport com.jnape.palatable.lambda.adt.Maybe;\nimport com.jnape.palatable.lambda.adt.hlist.Tuple2;\nimport com.jnape.palatable.shoki.api.Natural;\nimport com.jnape.palatable.shoki.api.Natural.NonZero;\nimport com.jnape.palatable.shoki.impl.TreeMultiSet;\nimport com.jnape.palatable.shoki.impl.TreeSet;\n\nimport static com.jnape.palatable.shoki.impl.TreeMultiSet.treeMultiSet;\nimport static java.util.Comparator.naturalOrder;\n\npublic class Example {\n\n    public static void main(String[] args) {\n        // same as treeMultiSet()\n        TreeMultiSet\u003cInteger\u003e empty = treeMultiSet(naturalOrder());\n\n        boolean                         _true     = empty.isEmpty();\n        Maybe\u003cTuple2\u003cInteger, NonZero\u003e\u003e nothing   = empty.head();\n        TreeMultiSet\u003cInteger\u003e           alsoEmpty = empty.tail();\n\n        TreeMultiSet\u003cInteger\u003e           _0x1_1x2_2x1     = empty.inc(0).inc(1).inc(2).inc(1);\n        boolean                         _false           = _0x1_1x2_2x1.isEmpty();\n        Maybe\u003cTuple2\u003cInteger, NonZero\u003e\u003e just0x1          = _0x1_1x2_2x1.head();\n        Maybe\u003cTuple2\u003cInteger, NonZero\u003e\u003e alsoJust0x1      = _0x1_1x2_2x1.min();\n        Maybe\u003cTuple2\u003cInteger, NonZero\u003e\u003e just2x1          = _0x1_1x2_2x1.max();\n        TreeMultiSet\u003cInteger\u003e           also_0x1_1x2_2x1 = empty.inc(1).inc(2).inc(1).inc(0);\n        boolean                         __true           = _0x1_1x2_2x1.contains(0);\n        boolean                         __false          = _0x1_1x2_2x1.contains(-1);\n\n        Natural one = _0x1_1x2_2x1.get(0);\n        Natural two = _0x1_1x2_2x1.get(1);\n\n        TreeMultiSet\u003cInteger\u003e           _1x2_2x1 = _0x1_1x2_2x1.tail();\n        Maybe\u003cTuple2\u003cInteger, NonZero\u003e\u003e just_1x2 = _1x2_2x1.head();\n\n        TreeMultiSet\u003cInteger\u003e           _2x1     = _1x2_2x1.tail();\n        Maybe\u003cTuple2\u003cInteger, NonZero\u003e\u003e just_2x1 = _2x1.head();\n\n        TreeMultiSet\u003cInteger\u003e _2x1_3x1_4x1         = treeMultiSet(2, 3, 4);\n        TreeMultiSet\u003cInteger\u003e _0x1_1x2_2x1_3x1_4x1 = _0x1_1x2_2x1.union(_2x1_3x1_4x1);\n        TreeMultiSet\u003cInteger\u003e _0x1_1x2             = _0x1_1x2_2x1.difference(_2x1_3x1_4x1);\n        TreeMultiSet\u003cInteger\u003e _0x1_1x2_3x1_4x1     = _0x1_1x2_2x1.symmetricDifference(_2x1_3x1_4x1);\n        TreeMultiSet\u003cInteger\u003e __2x1                = _0x1_1x2_2x1.intersection(_2x1_3x1_4x1);\n        TreeMultiSet\u003cInteger\u003e _0x1_1x2_2x2_3x1_4x1 = _0x1_1x2_2x1.sum(_2x1_3x1_4x1);\n\n        TreeSet\u003cInteger\u003e _012 = _0x1_1x2_2x1.unique();\n    }\n}\n```\n\n\u003ca name=\"license\"\u003eLicense\u003c/a\u003e\n-------\n\n_shōki_ is part of [palatable](http://www.github.com/palatable), which is distributed under \n[The MIT License](http://choosealicense.com/licenses/mit/).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpalatable%2Fshoki","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpalatable%2Fshoki","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpalatable%2Fshoki/lists"}