diff --git a/.changelogged.yaml b/.changelogged.yaml
new file mode 100644
index 00000000..46180488
--- /dev/null
+++ b/.changelogged.yaml
@@ -0,0 +1,14 @@
+changelogs:
+ - changelog: ChangeLog.md
+
+ ignore_files:
+ - "*ChangeLog*.md"
+ - .changelogged.yaml
+
+ ignore_commits: []
+
+branch: upstream/master
+
+entry_format: " - %message% (see [%link%](%id%));"
+
+editor_command: "nano -EiT 2"
diff --git a/.gitignore b/.gitignore
index 12b582d3..d3f6bf89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,15 @@ out
lib_managed
*.iws
.deps
-
-.idea/ant.xml
-.idea/workspace.xml
-
+.idea
+.gradle
+build
+*.iml
+.settings
+.classpath
+.project
+.DS_Store
+MANIFEST.MF
+*/bin/**
+*~
+/.nb-gradle/
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 97c9ca5c..00000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
deleted file mode 100644
index 3572571a..00000000
--- a/.idea/copyright/profiles_settings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index e206d70d..00000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
deleted file mode 100644
index 6dfb3353..00000000
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ /dev/null
@@ -1,541 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 3b312839..00000000
--- a/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/buildScala.xml b/.idea/libraries/buildScala.xml
deleted file mode 100644
index 08a0b2ce..00000000
--- a/.idea/libraries/buildScala.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/defScala.xml b/.idea/libraries/defScala.xml
deleted file mode 100644
index 0e41e13c..00000000
--- a/.idea/libraries/defScala.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/scala_2_7_7.xml b/.idea/libraries/scala_2_7_7.xml
deleted file mode 100644
index 431ff760..00000000
--- a/.idea/libraries/scala_2_7_7.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/scala_2_7_7__build_.xml b/.idea/libraries/scala_2_7_7__build_.xml
deleted file mode 100644
index efa820f0..00000000
--- a/.idea/libraries/scala_2_7_7__build_.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/scala_2_8_1.xml b/.idea/libraries/scala_2_8_1.xml
deleted file mode 100644
index 1c8f0c9e..00000000
--- a/.idea/libraries/scala_2_8_1.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/scalacheck_1_8.xml b/.idea/libraries/scalacheck_1_8.xml
deleted file mode 100644
index 7b919451..00000000
--- a/.idea/libraries/scalacheck_1_8.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index f0a82d40..00000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- http://www.w3.org/1999/xhtml
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index cf9fca0d..00000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml
deleted file mode 100644
index 922003b8..00000000
--- a/.idea/scopes/scope_settings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
deleted file mode 100644
index 3b000203..00000000
--- a/.idea/uiDesigner.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
-
-
-
-
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 275077f8..00000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..2fb30bf7
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,31 @@
+# Use faster, Docker-based container (instead of OpenVZ)
+sudo: false
+
+language: java
+
+jdk:
+ - openjdk8
+
+matrix:
+ fast_finish: true
+
+ include:
+
+ allow_failures:
+
+script:
+ - ./gradlew build --no-daemon
+
+env:
+ global:
+ - secure: Bun+1FZ29Q3dR9gZ/5brxcSf+zcY5tWrsqOA4GUb5bYCMyORuXQB0FYXuhKR4wB1pFrk1a9EYwRwSu3GwRJVWb+UzF0CNOWF/QG5tGPx32IOXScwlL/KonI4Vhs7Oc0fF4Wdb7euNrT27BU61jbUugjJ642b3n0VBYFYDdquprU=
+ - secure: QAxhjqLRa+WHKIzgIJPZ/rM5a5uzqG7E5rsC0YvB25cO712oYXmzsYPia/oSp0chXlYLYMfk2UnLeQCSx2e6ogXRRRa977Q+B33Nt0Hd9SGLtduv6DBrbA2ehLU12Ib4DWe5VhF5eueAunycYcllTvqA5h+pzTtEVbd68ZHncM4=
+
+before_cache:
+ - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
+ - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
+
+cache:
+ directories:
+ - $HOME/.gradle/caches/
+ - $HOME/.gradle/wrapper/
diff --git a/CNAME b/CNAME
new file mode 100644
index 00000000..f24adb94
--- /dev/null
+++ b/CNAME
@@ -0,0 +1 @@
+www.functionaljava.org
\ No newline at end of file
diff --git a/README b/README
deleted file mode 100644
index e5c7f631..00000000
--- a/README
+++ /dev/null
@@ -1,26 +0,0 @@
-Functional Java is an open source library that seeks to improve the experience of using the Java programming language in a production environment. The library implements several advanced programming concepts that assist in achieving composition-oriented development. Functional Java is written using vanilla Java 1.5 syntax and requires no external supporting libraries. The JAR file will work with your Java 1.5 project without any additional effort.
-
-Functional Java also serves as a platform for learning functional programming concepts by introducing these concepts using a familiar language. The library is intended for use in production applications and is thoroughly tested using the technique of automated specification-based testing with ScalaCheck.
-
-Functional Java includes the following features:
-
- * Fully operational Actors for parallel computations (fj.control.parallel) and layered abstractions such as parallel-map, map-reduce, parallel-zip.
- * A package (fj.data.fingertrees) providing 2-3 finger trees for a functional representation of persistent sequences supporting access to the ends in amortized O(1) time.
- * Type-safe heterogeneous list (fj.data.hlist) for lists of elements of differing types without sacrificing type-safety.
- * Monadic parser combinators for writing parsers by combining smaller parsers using composition.
- * Conversion of data types to/from standard Java types.
- * Immutable, in-memory singly linked list (fj.data.List).
- * Immutable lazy singly linked list (fj.data.Stream).
- * Array wrapper (fj.data.Array).
- * Optional value — type-safe null (fj.data.Option).
- * Disjoint union data type — compositional exception handling (fj.data.Either).
- * Monoid (fj.Monoid).
- * Functions with arity 1 to 8.
- * Products of 1 to 8.
- * Configurable equality and hash-code for HashMap and HashSet.
- * Natural number data type (fj.data.Natural).
- * Immutable set implementation using a red/black tree.
- * Immutable multi-way tree — aka rose tree (fj.data.Tree).
- * Immutable tree-map using a red/black tree implementation (fj.data.TreeMap).
- * Zipper implementations for streams and trees.
- * Automated specification-based testing framework (fj.test).
diff --git a/README.adoc b/README.adoc
new file mode 100644
index 00000000..ecf403e2
--- /dev/null
+++ b/README.adoc
@@ -0,0 +1,121 @@
+= Functional Java
+
+image:https://travis-ci.org/functionaljava/functionaljava.svg?branch=master["Build Status", link="https://app.travis-ci.com/github/functionaljava/functionaljava"]
+image:https://codecov.io/gh/functionaljava/functionaljava/branch/master/graph/badge.svg["Code Coverage", link="https://codecov.io/gh/functionaljava/functionaljava"]
+image:https://badges.gitter.im/functionaljava/functionaljava.svg[link="https://gitter.im/functionaljava/functionaljava?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
+
+image::http://www.functionaljava.org/img/logo-600x144.png[]
+
+Functional Java is an open source library facilitating functional programming in Java. The library implements numerous basic and advanced programming abstractions that assist composition oriented development. Functional Java also serves as a platform for learning functional programming concepts by introducing these concepts using a familiar language.
+
+The library is intended for use in production applications and is thoroughly tested using the technique of automated specification-based testing with ScalaCheck and Functional Java's quickcheck module.
+
+Functional Java provides abstractions for the following types:
+
+* Basic Data Structures - total and partial functions, products, unit, option, unbiased and right biased unions (either and validation), void.
+* Immutable Collections - array, list, vector, stream, set, map, priority queue, finger tree, heterogenous list, difference list.
+* Other Abstractions - monoid, semigroup, natural, random number generator, reader, writer, state, input/output, parser, zipper, specification based testing (quickcheck), actors, optics (lens, prism, fold, traversal and others), concurrency and type conversion.
+
+== URLs
+
+Important URLs for the project are:
+
+* Website, http://www.functionaljava.org
+* Website repository, http://github.com/functionaljava/functionaljava.github.io
+* Travis continuous integration build, https://app.travis-ci.com/github/functionaljava/functionaljava
+* Sonatype repository, https://oss.sonatype.org/content/groups/public/org/functionaljava/
+* Maven Central repository, https://mvnrepository.com/artifact/org.functionaljava/functionaljava
+
+== Downloading
+
+The recommended way to download and use the project is through your build tool.
+
+The Functional Java artifact is published to Maven Central using the group `org.functionaljava` with three published artifacts:
+
+* the core library (`functionaljava`)
+* property based testing (`functionaljava-quickcheck`)
+* a small amount of Java 8 support (`functionaljava-java-core`)
+
+The latest stable version is `5.0`. This can be added to your Gradle project by adding the dependencies:
+----
+compile "org.functionaljava:functionaljava:5.0"
+compile "org.functionaljava:functionaljava-quickcheck:5.0"
+compile "org.functionaljava:functionaljava-java-core:5.0"
+----
+
+and in Maven:
+----
+
+ org.functionaljava
+ functionaljava
+ 5.0
+
+
+ org.functionaljava
+ functionaljava-quickcheck
+ 5.0
+
+
+ org.functionaljava
+ functionaljava-java-core
+ 5.0
+
+----
+
+== Building
+
+Building is done using Java 8 and Gradle 7.4. In the root directory run:
+----
+./gradlew
+----
+This requires access to Java 8 and will download the Gradle build tool and necessary dependencies and build FunctionalJava.
+
+== Features
+
+A more complete description of the features mentioned above are:
+
+* Basic Data Structures
+** Functions with arity 1 to 8 (`fj.F`).
+** Functions with arity 0 to 8 that can produce exceptions (`fj.Try`).
+** Functions with arity 0 to 8 that have a void return (`fj.Effect`).
+** Functions with arity 0 to 8 that have a void return and can throw an exception (`fj.TryEffect`).
+** Products with arity 1 to 8 (`fj.P`).
+** Unit type (`fj.Unit`).
+** Optional value - _type-safe null_ (`fj.data.Option`).
+** Disjoint union data type - _compositional exception handling_ (`fj.data.Either`).
+** Validation - _right biased_ compositional exception handling (`fj.data.Validation`).
+* Immutable Collections
+** Array wrapper (`fj.data.Array`).
+** Immutable, in-memory singly linked list (`fj.data.List`).
+** Immutable lazy singly linked list (`fj.data.Stream`).
+** A package (`fj.data.fingertrees`) providing 2-3 finger trees for a functional representation of persistent sequences, supporting access to the ends in amortized O(1) time.
+** Type-safe heterogeneous list (`fj.data.hlist`) for lists of elements of differing types without sacrificing type-safety.
+** Immutable set implementation using a red/black tree (`fj.data.Set`).
+** Immutable multi-way tree - aka rose tree (`fj.data.Tree`).
+** Immutable tree-map using a red/black tree implementation (`fj.data.TreeMap`).
+** Immutable priority queue using finger trees (`fj.data.PriorityQueue`).
+** Difference lists, a highly performant list.
+* Other Abstractions
+** Monoid (`fj.Monoid`).
+** Semigroup (`fj.Semigroup`).
+** Natural number data type (`fj.data.Natural`).
+** Random number generator using a _linear congruential generator_ (`fj.LcgRng`).
+** Reader, Writer and State monads (`fj.data.Reader`,`fj.data.Writer`, `fj.data.State`).
+** Input/Output monad for abstracting IO (`fj.IO`).
+** Monadic parser combinators for writing parsers by combining smaller parsers using composition.
+** Conversion of data types to/from standard Java types.
+** Conversion between FunctionalJava and Java 8 specific types.
+** Configurable equality and hash-code for HashMap and HashSet.
+** Zipper implementations for streams and trees.
+** Automated specification-based testing framework (`fj.test`).
+** Fully operational Actors for parallel computations (`fj.control.parallel`) and layered abstractions such as parallel-map, map-reduce, parallel-zip.
+** Optics for updating immutable data including lens, prism, iso, optional, traversal, getter, fold and setter. Inspired by the Scala Monocle library (https://github.com/julien-truffaut/Monocle) and the Haskell lens library (https://github.com/ekmett/lens).
+** Void, a logically uninhabited type.
+
+== License
+
+link:etc/LICENCE[The Functional Java license] uses the BSD 3 license (3-clause license) available at https://en.wikipedia.org/wiki/BSD_licenses[].
+
+== Release Notes
+
+For release notes for each version, see the directory link:etc/release-notes.
diff --git a/build-maven.xml b/build-maven.xml
deleted file mode 100644
index 5cf7742b..00000000
--- a/build-maven.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 00000000..c89c9536
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,204 @@
+
+defaultTasks 'build'
+
+apply plugin: "com.github.ben-manes.versions"
+
+buildscript {
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+
+ dependencies {
+ classpath "com.github.ben-manes:gradle-versions-plugin:0.42.0"
+ classpath "biz.aQute.bnd:biz.aQute.bnd.gradle:6.1.0"
+ }
+
+ wrapper {
+ gradleVersion = "7.4"
+ distributionType = Wrapper.DistributionType.ALL
+ }
+}
+
+
+if (JavaVersion.current().isJava8Compatible()) {
+ allprojects {
+ tasks.withType(Javadoc) {
+ options.addStringOption('Xdoclint:none', '-quiet')
+ }
+ }
+}
+
+allprojects {
+
+ apply plugin: "jacoco"
+
+ jacoco {
+ toolVersion = "0.8.7"
+ }
+
+ defaultTasks "build"
+
+ ext {
+ isSnapshot = true
+ fjBaseVersion = "5.1"
+
+ snapshotAppendix = "-SNAPSHOT"
+ fjVersion = fjBaseVersion + (isSnapshot ? snapshotAppendix : "")
+ fjConsumeVersion = "5.0"
+
+ signModule = false
+ uploadModule = false
+
+ projectTitle = "Functional Java"
+ projectName = "functionaljava"
+ pomProjectName = projectTitle
+ pomOrganisation = projectTitle
+ projectDescription = "Functional Java is an open source library that supports closures for the Java programming language"
+ projectUrl = "http://functionaljava.org/"
+ scmUrl = "git://github.com/functionaljava/functionaljava.git"
+ scmGitFile = "scm:git@github.com:functionaljava/functionaljava.git"
+ scmSshGitFile = "scm:git:ssh://git@github.com/functionaljava/functionaljava.git"
+ licenseUrl = "https://github.com/functionaljava/functionaljava/blob/master/etc/LICENCE"
+ licenseName = "The BSD3 License"
+
+ issueUrl = "https://github.com/functionaljava/functionaljava/issues"
+ githubUrl = "https://github.com/functionaljava/functionaljava"
+
+ sonatypeBaseUrl = "https://oss.sonatype.org"
+ sonatypeSnapshotUrl = "$sonatypeBaseUrl/content/repositories/snapshots/"
+ sonatypeRepositoryUrl = "$sonatypeBaseUrl/content/groups/public"
+ sonatypeReleaseUrl = "$sonatypeBaseUrl/service/local/staging/deploy/maven2/"
+
+ sonatypeUploadUrl = isSnapshot ? sonatypeSnapshotUrl : sonatypeReleaseUrl
+
+ primaryEmail = "functionaljava@googlegroups.com"
+
+ junitCompile = "junit:junit:4.13.2"
+ junitRuntime = "org.junit.vintage:junit-vintage-engine:5.8.2"
+
+ displayCompilerWarnings = true
+ generateTestReports = false
+ }
+
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ }
+
+ version = fjVersion
+ group = "org.functionaljava"
+
+}
+
+subprojects {
+
+
+ buildscript {
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ }
+ }
+
+ apply from: "$rootDir/lib.gradle"
+ apply plugin: "java-library"
+ apply plugin: "eclipse"
+
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ maven {
+ url sonatypeRepositoryUrl
+ }
+ }
+
+ tasks.withType(JavaCompile) {
+ if (displayCompilerWarnings) {
+ options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
+ }
+ }
+
+ tasks.withType(Test).configureEach {
+ maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
+ if (!generateTestReports) {
+ reports.html.required = false
+ reports.junitXml.required = false
+ }
+ }
+
+
+}
+
+task coverage(type: org.gradle.testing.jacoco.tasks.JacocoReport) {
+ dependsOn = subprojects*.test
+ executionData fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec")
+ // We only care about coverage of:
+ def projectForFoverage = ["core", "quickcheck", "java-core"]
+ getClassDirectories().from(files(subprojects.findAll {subproject -> subproject.name in projectForFoverage} .sourceSets.main.output))
+ getSourceDirectories().from(files(subprojects.findAll {subproject -> subproject.name in projectForFoverage} .sourceSets.main.allSource.srcDirs))
+
+ reports {
+ html.required = true
+ xml.required = true
+ }
+}
+
+configure(subprojects.findAll { it.name != "props-core" }) {
+
+ apply plugin: "maven-publish"
+ apply plugin: "signing"
+ apply plugin: "biz.aQute.bnd.builder"
+ sourceCompatibility = "1.8"
+
+ javadoc {
+ }
+
+ task javadocJar(type: Jar, dependsOn: "javadoc") {
+ classifier = 'javadoc'
+ from "build/docs/javadoc"
+ }
+
+ task sourcesJar(type: Jar) {
+ from sourceSets.main.allSource
+ classifier = 'sources'
+ }
+
+ artifacts {
+ archives jar
+ archives javadocJar
+ archives sourcesJar
+ }
+
+ jar {
+ archiveVersion = project.fjVersion
+ bnd (
+ 'Bundle-Name': 'Functional Java',
+ 'Signature-Version': project.fjVersion,
+ 'Bundle-ActivationPolicy': 'lazy',
+ 'Bundle-Vendor': 'functionaljava.org',
+ 'Automatic-Module-Name': "functionaljava${project.name == 'core' ? '' : ".$project.name"}",
+ )
+ }
+
+ eclipse {
+ project {
+ natures 'org.eclipse.pde.PluginNature'
+ buildCommand 'org.eclipse.pde.ManifestBuilder'
+ buildCommand 'org.eclipse.pde.SchemaBuilder'
+ }
+ }
+
+ // Output MANIFEST.MF statically so eclipse can see it for plugin development
+ task eclipsePluginManifest(dependsOn: jar) doLast {
+ file("META-INF").mkdirs()
+ jar.manifest.writeTo(file("META-INF/MANIFEST.MF"))
+ }
+
+ eclipseProject.dependsOn eclipsePluginManifest
+}
+
+task env doLast {
+ println System.getenv()
+}
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 00000000..b7ddeec5
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,4 @@
+ignore:
+ - "demo/.*"
+ - "consume/.*"
+ - "performance/.*"
diff --git a/consume/build.gradle b/consume/build.gradle
new file mode 100644
index 00000000..45dadefb
--- /dev/null
+++ b/consume/build.gradle
@@ -0,0 +1,9 @@
+
+archivesBaseName = "${project.projectName}-${project.name}"
+
+dependencies {
+ api "$group:$projectName:$fjConsumeVersion"
+
+ testImplementation junitCompile
+ testRuntimeOnly junitRuntime
+}
diff --git a/consume/src/main/java/fj/consume/euler/Problem1.java b/consume/src/main/java/fj/consume/euler/Problem1.java
new file mode 100644
index 00000000..d3bf7962
--- /dev/null
+++ b/consume/src/main/java/fj/consume/euler/Problem1.java
@@ -0,0 +1,21 @@
+package fj.consume.euler;
+
+import static fj.data.List.range;
+import static fj.function.Integers.sum;
+
+import static java.lang.System.out;
+
+/**
+ * Add all the natural numbers below one thousand that are multiples of 3 or 5.
+ */
+public class Problem1 {
+
+ public static void main(final String[] args) {
+ calc();
+ }
+
+ public static void calc() {
+ out.println(sum(range(0, 1000).filter(a -> a % 3 == 0 || a % 5 == 0)));
+ }
+
+}
diff --git a/consume/src/test/java/fj/EmptyTest.java b/consume/src/test/java/fj/EmptyTest.java
new file mode 100644
index 00000000..13675822
--- /dev/null
+++ b/consume/src/test/java/fj/EmptyTest.java
@@ -0,0 +1,15 @@
+package fj;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.junit.Assert;
+
+public class EmptyTest {
+
+ @Ignore @Test
+ public void missing() {
+ Assert.fail("not implemented");
+
+ }
+}
diff --git a/core/build.gradle b/core/build.gradle
new file mode 100644
index 00000000..282ec191
--- /dev/null
+++ b/core/build.gradle
@@ -0,0 +1,18 @@
+
+ext {
+ signModule = true
+ uploadModule = true
+
+}
+
+archivesBaseName = project.projectName
+
+dependencies {
+ testImplementation junitCompile
+ testRuntimeOnly junitRuntime
+ testImplementation 'com.h2database:h2:2.1.210'
+ testImplementation 'commons-dbutils:commons-dbutils:1.7'
+}
+
+performSigning(signingEnabled, signModule)
+configureUpload(signingEnabled, signModule, uploadModule)
diff --git a/core/functionaljava-core.iml b/core/functionaljava-core.iml
deleted file mode 100644
index 6c3a7ded..00000000
--- a/core/functionaljava-core.iml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/core/src/main/java/fj/Bottom.java b/core/src/main/java/fj/Bottom.java
index 6c475bd4..5cc7f4e4 100644
--- a/core/src/main/java/fj/Bottom.java
+++ b/core/src/main/java/fj/Bottom.java
@@ -2,8 +2,6 @@
/**
* Represents the bottom _|_ value.
- *
- * @version %build.number%
*/
public final class Bottom {
private Bottom() {
@@ -38,11 +36,9 @@ public static Error error(final String s) {
* @return A thunk that throws an error using the given message when evaluated.
*/
public static P1 error_(final String s) {
- return new P1() {
- @Override public A _1() {
+ return P.lazy(() -> {
throw new Error(s);
- }
- };
+ });
}
/**
@@ -52,10 +48,8 @@ public static P1 error_(final String s) {
* @return A function that throws an error using the given message, ignoring its argument.
*/
public static F errorF(final String s) {
- return new F() {
- public B f(final A a) {
+ return a -> {
throw new Error(s);
- }
};
}
@@ -76,7 +70,7 @@ public static Error decons(final A a, final Show sa) {
* @param c The type being deconstructed.
* @return A deconstruction failure that was non-exhaustive.
*/
- @SuppressWarnings({"UnnecessaryFullyQualifiedName"})
+ @SuppressWarnings("UnnecessaryFullyQualifiedName")
public static Error decons(final java.lang.Class c) {
return error("Deconstruction failure on type " + c);
}
@@ -87,11 +81,7 @@ public static Error decons(final java.lang.Class c) {
* @return A function that returns the toString for a throwable.
*/
public static F eToString() {
- return new F() {
- public String f(final Throwable t) {
- return t.toString();
- }
- };
+ return Throwable::toString;
}
/**
@@ -100,10 +90,6 @@ public String f(final Throwable t) {
* @return A function that returns the getMessage for a throwable.
*/
public static F eMessage() {
- return new F() {
- public String f(final Throwable t) {
- return t.getMessage();
- }
- };
+ return Throwable::getMessage;
}
}
diff --git a/core/src/main/java/fj/Bounded.java b/core/src/main/java/fj/Bounded.java
new file mode 100644
index 00000000..e100b6d6
--- /dev/null
+++ b/core/src/main/java/fj/Bounded.java
@@ -0,0 +1,50 @@
+package fj;
+
+/**
+ * The Bounded class is used to name the upper and lower limits of a type.
+ * Ord is not a superclass of Bounded since types that are not totally ordered may also have upper and lower bounds.
+ */
+public final class Bounded {
+
+ private final Definition def;
+
+ /**
+ * Minimal definition of Bounded
+ */
+ public interface Definition {
+ A min();
+
+ A max();
+ }
+
+ private Bounded(Definition definition) {
+ this.def = definition;
+ }
+
+ public A min() {
+ return def.min();
+ }
+
+ public A max() {
+ return def.max();
+ }
+
+ public static Bounded boundedDef(Definition def) {
+ return new Bounded<>(def);
+ }
+
+ public static Bounded bounded(A min, A max) {
+ return boundedDef(new Definition() {
+ @Override
+ public A min() {
+ return min;
+ }
+
+ @Override
+ public A max() {
+ return max;
+ }
+ });
+ }
+
+}
diff --git a/core/src/main/java/fj/Class.java b/core/src/main/java/fj/Class.java
index 9e02c4e4..8bee1951 100644
--- a/core/src/main/java/fj/Class.java
+++ b/core/src/main/java/fj/Class.java
@@ -2,7 +2,6 @@
import fj.data.List;
import static fj.data.List.unfold;
-import fj.data.Option;
import static fj.data.Option.none;
import static fj.data.Option.some;
import fj.data.Tree;
@@ -12,8 +11,6 @@
/**
* A wrapper for a {@link java.lang.Class} that provides additional methods.
- *
- * @version %build.number%
*/
public final class Class {
private final java.lang.Class c;
@@ -29,31 +26,24 @@ private Class(final java.lang.Class c) {
*/
public List> inheritance() {
return unfold(
- new F, Option, java.lang.Class super T>>>>() {
- public Option, java.lang.Class super T>>> f(
- final java.lang.Class super T> c) {
- if (c == null)
- return none();
- else {
- final P2, java.lang.Class super T>> p =
- new P2, java.lang.Class super T>>() {
- public java.lang.Class super T> _1() {
- return c;
- }
+ (java.lang.Class super T> c2) -> {
+ if (c2 == null)
+ return none();
+ else {
+ final P2, java.lang.Class super T>> p =
+ new P2, java.lang.Class super T>>() {
+ public java.lang.Class super T> _1() {
+ return c2;
+ }
- @SuppressWarnings({"unchecked"})
- public java.lang.Class super T> _2() {
- return c.getSuperclass();
- }
- };
- return some(p);
- }
- }
- }, c).map(new F, Class super T>>() {
- public Class super T> f(final java.lang.Class super T> c) {
- return clas(c);
- }
- });
+ @SuppressWarnings("unchecked")
+ public java.lang.Class super T> _2() {
+ return c2.getSuperclass();
+ }
+ };
+ return some(p);
+ }
+ }, c).map(Class::clas);
}
/**
@@ -109,7 +99,7 @@ public static Tree typeParameterTree(final Type t) {
}
types = Tree.node(pt.getRawType(), typeArgs);
} else {
- types = Tree.node(t, List.>nil());
+ types = Tree.node(t, List.nil());
}
return types;
}
@@ -130,6 +120,6 @@ public java.lang.Class clas() {
* @return A class from the given argument.
*/
public static Class clas(final java.lang.Class c) {
- return new Class(c);
+ return new Class<>(c);
}
}
diff --git a/core/src/main/java/fj/Digit.java b/core/src/main/java/fj/Digit.java
index ed6e86ab..4fec7b0c 100644
--- a/core/src/main/java/fj/Digit.java
+++ b/core/src/main/java/fj/Digit.java
@@ -6,8 +6,6 @@
/**
* The digits zero to nine.
- *
- * @version %build.number%
*/
public enum Digit {
/**
@@ -176,36 +174,20 @@ public static Option fromChar(final char c) {
/**
* First-class conversion from digit to a long.
*/
- public static final F toLong = new F() {
- public Long f(final Digit d) {
- return d.toLong();
- }
- };
+ public static final F toLong = Digit::toLong;
/**
* First-class conversion from a long to a digit.
*/
- public static final F fromLong = new F() {
- public Digit f(final Long i) {
- return fromLong(i);
- }
- };
+ public static final F fromLong = Digit::fromLong;
/**
* First-class conversion from a digit to a character.
*/
- public static final F toChar = new F() {
- public Character f(final Digit d) {
- return d.toChar();
- }
- };
+ public static final F toChar = Digit::toChar;
/**
* First-class conversion from a character to a digit.
*/
- public static final F> fromChar = new F>() {
- public Option f(final Character c) {
- return fromChar(c);
- }
- };
+ public static final F> fromChar = Digit::fromChar;
}
diff --git a/core/src/main/java/fj/Effect.java b/core/src/main/java/fj/Effect.java
index 46bda819..2b5dcd6f 100644
--- a/core/src/main/java/fj/Effect.java
+++ b/core/src/main/java/fj/Effect.java
@@ -1,49 +1,107 @@
package fj;
+import fj.function.Effect0;
+import fj.function.Effect1;
+import fj.function.Effect2;
+import fj.function.Effect3;
+import fj.function.Effect4;
+import fj.function.Effect5;
+import fj.function.Effect6;
+import fj.function.Effect7;
+import fj.function.Effect8;
+
import static fj.Unit.unit;
/**
* Represents a side-effect.
- *
- * @version %build.number%
*/
-public abstract class Effect {
- public abstract void e(A a);
+public final class Effect {
+
+ private Effect() {}
+ public static P1 f(Effect0 e) {
+ return P.lazy(() -> {
+ e.f();
+ return unit();
+ });
+ }
- /**
+ /**
* Returns a function for the given effect.
*
* @return The function using the given effect.
*/
- public final F e() {
- return new F() {
- public Unit f(final A a) {
- e(a);
+ public static F f(Effect1 e1) {
+ return a -> {
+ e1.f(a);
return unit();
- }
};
}
- /**
+ public static F2 f(Effect2 e) {
+ return (a, b) -> {
+ e.f(a, b);
+ return unit();
+ };
+ }
+
+ public static F3 f(Effect3 e) {
+ return (a, b, c) -> {
+ e.f(a, b, c);
+ return unit();
+ };
+ }
+
+ public static F4 f(Effect4 e) {
+ return (a, b, c, d) -> {
+ e.f(a, b, c, d);
+ return unit();
+ };
+ }
+
+ public static F5 f(Effect5 z) {
+ return (a, b, c, d, e) -> {
+ z.f(a, b, c, d, e);
+ return unit();
+ };
+ }
+
+ public static F6 f(Effect6 z) {
+ return (a, b, c, d, e, f) -> {
+ z.f(a, b, c, d, e, f);
+ return unit();
+ };
+ }
+
+ public static F7 f(Effect7 z) {
+ return (a, b, c, d, e, f, g) -> {
+ z.f(a, b, c, d, e, f, g);
+ return unit();
+ };
+ }
+
+ public static F8 f(Effect8 z) {
+ return (a, b, c, d, e, f, g, h) -> {
+ z.f(a, b, c, d, e, f, g, h);
+ return unit();
+ };
+ }
+
+ /**
* A contra-variant functor on effect.
*
* @param f The function to map over the effect.
* @return An effect after a contra-variant map.
*/
- public final Effect comap(final F f) {
- return new Effect() {
- public void e(final B b) {
- Effect.this.e(f.f(b));
- }
- };
+ public static Effect1 contramap(Effect1 e1, final F f) {
+ return b -> e1.f(f.f(b));
}
- public static Effect f(final F f) {
- return new Effect() {
- public void e(final A a) {
- f.f(a);
- }
- };
+ public static Effect1 lazy(final F f) {
+ return f::f;
+
}
+
+// public static void f(Effect1 )
+
}
diff --git a/core/src/main/java/fj/Equal.java b/core/src/main/java/fj/Equal.java
index ff0362e2..cba4a589 100644
--- a/core/src/main/java/fj/Equal.java
+++ b/core/src/main/java/fj/Equal.java
@@ -1,17 +1,9 @@
package fj;
-import static fj.Function.curry;
+import fj.data.*;
+import fj.data.hamt.BitSet;
import fj.data.hlist.HList;
-import fj.data.Array;
-import fj.data.Either;
-import fj.data.LazyString;
-import fj.data.List;
-import fj.data.NonEmptyList;
-import fj.data.Option;
-import fj.data.Set;
-import fj.data.Stream;
-import fj.data.Tree;
-import fj.data.Validation;
+import fj.data.optic.Traversal;
import fj.data.vector.V2;
import fj.data.vector.V3;
import fj.data.vector.V4;
@@ -19,20 +11,83 @@
import fj.data.vector.V6;
import fj.data.vector.V7;
import fj.data.vector.V8;
+import fj.parser.Result;
-import java.math.BigInteger;
import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import static fj.Function.compose;
+import static fj.Function.constant;
+import static fj.Function.curry;
/**
* Tests for equality between two objects.
- *
- * @version %build.number%
*/
public final class Equal {
- private final F> f;
- private Equal(final F> f) {
- this.f = f;
+ /**
+ * Primitives functions of Equal: minimal definition and overridable methods.
+ */
+ public interface Definition {
+
+ F equal(A a);
+
+ default boolean equal(A a1, A a2) {
+ return equal(a1).f(a2);
+ }
+
+ /**
+ * Refine this equal definition, to tests equality of self and the mapped object in "and" manner.
+ * @see #equal()
+ *
+ * @param f The function to map the original object
+ * @param eq Equality for the mapped object
+ * @return A new equal definition
+ */
+ default Definition then(final F f, final Equal eq) {
+ Definition bEqDef = eq.def;
+ return new Definition() {
+ @Override
+ public F equal(A a1) {
+ F fa = Definition.this.equal(a1);
+ F fb = bEqDef.equal(f.f(a1));
+ return a2 -> fa.f(a2) && fb.f(f.f(a2));
+ }
+
+ @Override
+ public boolean equal(A a1, A a2) {
+ return Definition.this.equal(a1, a2) && bEqDef.equal(f.f(a1), f.f(a2));
+ }
+ };
+ }
+
+ /**
+ * Build an equal instance from this definition.
+ * to be called after some successive {@link #then(F, Equal)} calls.
+ */
+ default Equal equal() {
+ return equalDef(this);
+ }
+ }
+
+ /**
+ * Primitives functions of Equal: alternative minimal definition and overridable methods.
+ */
+ public interface AltDefinition extends Definition {
+
+ @Override
+ boolean equal(A a1, A a2);
+
+ @Override
+ default F equal(A a) {
+ return a2 -> equal(a, a2);
+ }
+ }
+
+ private final Definition def;
+
+ private Equal(final Definition def) {
+ this.def = def;
}
/**
@@ -43,7 +98,18 @@ private Equal(final F> f) {
* @return true if the two given arguments are equal, false otherwise.
*/
public boolean eq(final A a1, final A a2) {
- return f.f(a1).f(a2);
+ return def.equal(a1, a2);
+ }
+
+ /**
+ * Returns true if the two given arguments are not equal, false otherwise.
+ *
+ * @param a1 An object to test for inequality against another.
+ * @param a2 An object to test for inequality against another.
+ * @return true if the two given arguments are not equal, false otherwise.
+ */
+ public boolean notEq(final A a1, final A a2) {
+ return !def.equal(a1, a2);
}
/**
@@ -52,11 +118,7 @@ public boolean eq(final A a1, final A a2) {
* @return A function that returns true if the two given arguments are equal.
*/
public F2 eq() {
- return new F2() {
- public Boolean f(final A a, final A a1) {
- return eq(a, a1);
- }
- };
+ return def::equal;
}
/**
@@ -66,11 +128,7 @@ public Boolean f(final A a, final A a1) {
* @return A function that returns true if the given argument equals the argument to this method.
*/
public F eq(final A a) {
- return new F() {
- public Boolean f(final A a1) {
- return eq(a, a1);
- }
- };
+ return def.equal(a);
}
/**
@@ -79,18 +137,92 @@ public Boolean f(final A a1) {
* @param f The function to map.
* @return A new equal.
*/
- public Equal comap(final F f) {
- return equal(f.andThen().o(this.f).o(f));
+ public Equal contramap(final F f) {
+ return equalDef(contramapDef(f, def));
+ }
+
+ /**
+ * An equal instance, which reverts equality for self
+ *
+ * @return A new equal instance
+ */
+ public final Equal not() {
+ return equalDef((a1, a2) -> !def.equal(a1, a2));
+ }
+
+
+ private static Definition contramapDef(F f, Definition aEqDef) {
+ return new Definition(){
+ @Override
+ public F equal(B b) {
+ return compose(aEqDef.equal(f.f(b)), f);
+ }
+
+ @Override
+ public boolean equal(B b1, B b2) {
+ return aEqDef.equal(f.f(b1), f.f(b2));
+ }
+ };
+ }
+
+ /**
+ * Static version of {@link #contramap(F)}
+ */
+ public static Equal contramap(final F f, final Equal eq) {
+ return eq.contramap(f);
+ }
+
+ /**
+ * Begin definition of an equal instance.
+ * @see Definition#then(F, Equal)
+ */
+ public static Definition on(final F f, final Equal eq) {
+ return contramapDef(f, eq.def);
}
/**
* Constructs an equal instance from the given function.
*
+ * Java 8+ users: use {@link #equalDef(Definition)} instead.
+ *
* @param f The function to construct the equal with.
* @return An equal instance from the given function.
*/
public static Equal equal(final F> f) {
- return new Equal(f);
+ return new Equal<>(f::f);
+ }
+
+
+ /**
+ * Constructs an equal instance from the given function.
+ *
+ * Java 8+ users: use {@link #equalDef(AltDefinition)} instead.
+ *
+ * @param f The function to construct the equal with.
+ * @return An equal instance from the given function.
+ */
+ public static Equal equal(final F2 f) {
+ return equalDef(f::f);
+ }
+
+ /**
+ * Constructs an equal instance from the given definition.
+ *
+ * @param definition a definition of the equal instance.
+ * @return An equal instance from the given function.
+ */
+ public static Equal equalDef(final Definition definition) {
+ return new Equal<>(definition);
+ }
+
+ /**
+ * Constructs an equal instance from the given (alternative) definition.
+ *
+ * @param definition a definition of the equal instance.
+ * @return An equal instance from the given function.
+ */
+ public static Equal equalDef(final AltDefinition definition) {
+ return new Equal<>(definition);
}
/**
@@ -101,13 +233,15 @@ public static Equal equal(final F> f) {
* equality.
*/
public static Equal anyEqual() {
- return new Equal(new F>() {
- public F f(final A a1) {
- return new F() {
- public Boolean f(final A a2) {
- return a1.equals(a2);
- }
- };
+ return equalDef(new Definition() {
+ @Override
+ public F equal(A a) {
+ return a::equals;
+ }
+
+ @Override
+ public boolean equal(A a1, A a2) {
+ return a1.equals(a2);
}
});
}
@@ -162,6 +296,11 @@ public Boolean f(final A a2) {
*/
public static final Equal shortEqual = anyEqual();
+ /**
+ * An equal instance for the Natural type.
+ */
+ public static final Equal naturalEqual = bigintEqual.contramap(Natural::bigIntegerValue);
+
/**
* An equal instance for the {@link String} type.
*/
@@ -171,42 +310,35 @@ public Boolean f(final A a2) {
* An equal instance for the {@link StringBuffer} type.
*/
public static final Equal stringBufferEqual =
- new Equal(new F>() {
- public F f(final StringBuffer sb1) {
- return new F() {
- public Boolean f(final StringBuffer sb2) {
- if (sb1.length() == sb2.length()) {
- for (int i = 0; i < sb1.length(); i++)
- if (sb1.charAt(i) != sb2.charAt(i))
- return false;
- return true;
- } else
- return false;
- }
- };
- }
+ equalDef((sb1, sb2) -> {
+ if (sb1.length() == sb2.length()) {
+ for (int i = 0; i < sb1.length(); i++)
+ if (sb1.charAt(i) != sb2.charAt(i))
+ return false;
+ return true;
+ } else
+ return false;
});
/**
* An equal instance for the {@link StringBuilder} type.
*/
public static final Equal stringBuilderEqual =
- new Equal(new F>() {
- public F f(final StringBuilder sb1) {
- return new F() {
- public Boolean f(final StringBuilder sb2) {
- if (sb1.length() == sb2.length()) {
- for (int i = 0; i < sb1.length(); i++)
- if (sb1.charAt(i) != sb2.charAt(i))
- return false;
- return true;
- } else
- return false;
- }
- };
- }
+ equalDef((sb1, sb2) -> {
+ if (sb1.length() == sb2.length()) {
+ for (int i = 0; i < sb1.length(); i++)
+ if (sb1.charAt(i) != sb2.charAt(i))
+ return false;
+ return true;
+ } else
+ return false;
});
+ /**
+ * An equal instance for the {@link BitSet} type.
+ */
+ public static final Equal bitSetSequal = equalDef((bs1, bs2) -> bs1.longValue() == bs2.longValue());
+
/**
* An equal instance for the {@link Either} type.
*
@@ -215,18 +347,29 @@ public Boolean f(final StringBuilder sb2) {
* @return An equal instance for the {@link Either} type.
*/
public static Equal> eitherEqual(final Equal ea, final Equal eb) {
- return new Equal>(new F, F, Boolean>>() {
- public F, Boolean> f(final Either e1) {
- return new F, Boolean>() {
- public Boolean f(final Either e2) {
- return e1.isLeft() && e2.isLeft() && ea.f.f(e1.left().value()).f(e2.left().value()) ||
- e1.isRight() && e2.isRight() && eb.f.f(e1.right().value()).f(e2.right().value());
- }
- };
- }
- });
+ Definition eaDef = ea.def;
+ Definition ebDef = eb.def;
+ return equalDef(e1 -> e1.either(
+ a1 -> Either.either_(eaDef.equal(a1), (B __) -> false),
+ b1 -> Either.either_((A __)-> false, ebDef.equal(b1))
+ ));
+ }
+
+ public static Equal> either3Equal(Equal ea, Equal eb, Equal ec) {
+ return equalDef((e1, e2) ->
+ optionEqual(ea).eq(e1.leftOption(), e2.leftOption()) &&
+ optionEqual(eb).eq(e1.middleOption(), e2.middleOption()) &&
+ optionEqual(ec).eq(e1.rightOption(), e2.rightOption())
+ );
+ }
+
+ public static Equal> resultEqual(final Equal ea, final Equal ei) {
+ Definition eaDef = ea.def;
+ Definition eiDef= ei.def;
+ return equalDef((r1, r2) -> eaDef.equal(r1.value(), r2.value()) && eiDef.equal(r1.rest(), r2.rest()));
}
+
/**
* An equal instance for the {@link Validation} type.
*
@@ -235,7 +378,7 @@ public Boolean f(final Either e2) {
* @return An equal instance for the {@link Validation} type.
*/
public static Equal> validationEqual(final Equal ea, final Equal eb) {
- return eitherEqual(ea, eb).comap(Validation.either());
+ return eitherEqual(ea, eb).contramap(Validation.either());
}
/**
@@ -245,25 +388,20 @@ public static Equal> validationEqual(final Equal ea,
* @return An equal instance for the {@link List} type.
*/
public static Equal> listEqual(final Equal ea) {
- return new Equal>(new F, F, Boolean>>() {
- public F, Boolean> f(final List a1) {
- return new F, Boolean>() {
- public Boolean f(final List a2) {
- List x1 = a1;
- List x2 = a2;
-
- while (x1.isNotEmpty() && x2.isNotEmpty()) {
- if (!ea.eq(x1.head(), x2.head()))
- return false;
-
- x1 = x1.tail();
- x2 = x2.tail();
- }
-
- return x1.isEmpty() && x2.isEmpty();
- }
- };
+ Definition eaDef = ea.def;
+ return equalDef((a1, a2) -> {
+ List x1 = a1;
+ List x2 = a2;
+
+ while (x1.isNotEmpty() && x2.isNotEmpty()) {
+ if (!eaDef.equal(x1.head(), x2.head()))
+ return false;
+
+ x1 = x1.tail();
+ x2 = x2.tail();
}
+
+ return x1.isEmpty() && x2.isEmpty();
});
}
@@ -274,7 +412,7 @@ public Boolean f(final List a2) {
* @return An equal instance for the {@link NonEmptyList} type.
*/
public static Equal> nonEmptyListEqual(final Equal ea) {
- return listEqual(ea).comap(NonEmptyList.toList_());
+ return listEqual(ea).contramap(NonEmptyList.toList_());
}
/**
@@ -284,16 +422,15 @@ public static Equal> nonEmptyListEqual(final Equal ea) {
* @return An equal instance for the {@link Option} type.
*/
public static Equal