Skip to content

Commit

Permalink
Merge pull request #15 from DerYeger/release/v2.0.0
Browse files Browse the repository at this point in the history
Release/v2.0.0
  • Loading branch information
DerYeger authored Sep 19, 2019
2 parents 992a743 + 031d2ac commit b1d7347
Show file tree
Hide file tree
Showing 40 changed files with 790 additions and 777 deletions.
2 changes: 1 addition & 1 deletion .idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 35 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Primitive Recursive Functions
# Refunk

> Primitive recursive functions made simple with Kotlin
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Release](https://jitpack.io/v/DerYeger/primitive-recursive-functions.svg)](https://jitpack.io/#DerYeger/primitive-recursive-functions)
[![Release](https://jitpack.io/v/DerYeger/refunk.svg)](https://jitpack.io/#DerYeger/refunk)

A small and lightweight library for studying and evaluating primitive recursive functions in Kotlin.

Expand All @@ -21,7 +21,7 @@ allprojects {
```
```
dependencies {
implementation 'com.github.DerYeger:primitive-recursive-functions:v1.1.0'
implementation 'com.github.DerYeger:refunk:v2.0.0'
}
```

Expand All @@ -38,70 +38,76 @@ dependencies {
```
<dependency>
<groupId>com.github.DerYeger</groupId>
<artifactId>primitive-recursive-functions</artifactId>
<version>v1.1.0</version>
<artifactId>refunk</artifactId>
<version>v2.0.0</version>
</dependency>
```

## Usage

### Basic functions

- `val c = Constant(value)`
- `val c = Constant(value)` with macros `c(value)`, `zero()` and `one()`.
- `val s = Successor()`
- `val p = Projection(index)`
- `val myRecursion = Recursion(myBaseCaseFunction, myRecursiveCaseFunction)`
- `val p = Projection(index)` with macros `p(index)`, `first()`, `second()` and `third()`.

### Composition

Composed functions like `(args) -> f(g1(args), ..., gn(args))` can be created with the `Composition` class
Composed functions like `(args) -> f(g1(args), ..., gn(args))` can be created with the `Composition` class and various extension methods.
```
val f = ...
val g1 = ...
...
val gn = ...
val myComposition = Composition(f, g1, ..., gn)
```
or by using `Function::compose`.
```
val myComposition = f.compose(g1, ..., gn)
val myExplicitComposition = Composition(f, g1, ..., gn)
val myMethodComposition = f.compose(g1, ..., gn)
val myInfixComposition = f of { g1 and ... and gn }
```
Unary functions can also be composed by using `Function::andThen`
```
val myComposition = myFunction.andThen(myUnaryFunction)
val myInfixComposition = myFunction andThen myUnaryFunction
```

### Recursion

Recursions can also be created using multiple extension methods.

```
val myClassicRecursion = Recursion(myBaseCaseFunction, myRecursiveCaseFunction)
... = recursive(myRecursiveCaseFunction) withBaseCase myBaseCaseFunction
... = recursive { myRecursiveCaseFunction of myHelperFunction } withBaseCase { someFunction andThen someOtherFunction }
```

### Evaluation

`Function::apply` returns the result for the given arguments.
```
val plusTwo = Successor().andThen(Successor())
val plusTwo = Successor() andThen Successor()
println(plusTwo.apply(0)) //prints 2
println(plusTwo.apply(40)) //prints 42
```
Projection and Successor are evaluated lazily, meaning only the required argument is evaluated.\
By default, Composition and and Recursion are not lazy. However, both can be set to evaluate lazily as well.
Projection, Successor, Recursion and composition with andThen are evaluated lazily, meaning only the required arguments are evaluated.\
In order to avoid StackOverflowErrors, Composition is not lazy. However, compositions (with the exception of infix compositions) can be set to evaluate lazily as well.
```
val myLazyComposition = Composition(myEvaluator, myFunctions, lazy = true)
... = myEvaluator.compose(myFunctions, lazy = true)
... = myFunction.andThen(myUnaryFunction, lazy = true)
val myLazyRecursion = Recursion(myBaseCaseFunction, myRecursiveCaseFunction, lazy = true)
```
Additional examples and various macros can be found [here](src/main/kotlin/eu/yeger/prf/Functions.kt).\
Non-recursive [implementations](src/main/kotlin/eu/yeger/prf/non_recursive/NonRecursiveFunctions.kt) of all macros are included as well.\
They are interchangeable with the recursive implementations and provide improved performance (and less StackOverflowErrors).
Additional examples and various macros can be found [here](src/main/kotlin/eu/yeger/refunk/recursive/RecursiveFunctions.kt).\
Non-recursive [implementations](src/main/kotlin/eu/yeger/refunk/non_recursive/NonRecursiveFunctions.kt) of all macros are included as well.\
They are interchangeable with the recursive implementations and provide improved performance (and less StackOverflowErrors).\
Using the non-recursive implementations of macros is highly recommended.

## Exceptions
## Exceptions and error handling

- Evaluating a function will throw an `ArityException` if not enough arguments were passed.
- Setting the arity of a function to a negative value will throw an `ArityException`.
- Projecting a negative index will throw a `ProjectionException`.
- Composing functions will throw a `CompositionException` if the arity of the evaluating function is not met.
- Composing with `andThen` will throw a `CompositionException` if the parameter is not an unary function.
- Negative values will, at any point during the evaluation and instantiation, throw a `NaturalNumberException`.
- Evaluating a `Successor` function will throw a `NaturalNumberException` if it would cause an overflow. **Note**: None of the non-recursive macros will throw an exception in this case, and instead set the value to 0.
- Composing functions will throw a `CompositionException` if the arity of the evaluating function and the number of provided functions do not match.
- Applying or creating constants with negative values will throw a `NaturalNumberException`.
- Any provided method will throw an `OverflowException` if an overflow occurs during evaluation.

## Intention
## Disclaimer

This library is intended as a tool for studying primitive recursive functions, since evaluating them by hand can be quite tedious.\
This library is intended as a tool for studying primitive recursive functions.\
Because the implementation is based on experimental Kotlin features, using them in production is not recommended.
12 changes: 6 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.50'
id "org.jetbrains.kotlin.jvm" version "1.3.50"
}

group 'eu.yeger'
version '1.1.0'
group "eu.yeger"
version "v2.0.0"

repositories {
mavenCentral()
}

dependencies {
testCompile "junit:junit:4.12"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
testImplementation("junit:junit:4.12")
}

compileKotlin {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions {
freeCompilerArgs = ["-XXLanguage:+InlineClasses"]
jvmTarget = "1.8"
}
}

Expand Down
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
rootProject.name = 'prf'
rootProject.name = 'refunk'

28 changes: 0 additions & 28 deletions src/main/kotlin/eu/yeger/prf/Argument.kt

This file was deleted.

39 changes: 0 additions & 39 deletions src/main/kotlin/eu/yeger/prf/Function.kt

This file was deleted.

Loading

0 comments on commit b1d7347

Please sign in to comment.