-
Notifications
You must be signed in to change notification settings - Fork 451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Function1 #137
Add Function1 #137
Changes from all commits
b0d38e2
35ef5b4
ba17ce9
4f398fc
02fe432
27dbeef
ac04952
66d56bc
b323cc6
7fe15ea
197b410
552d0c9
48a0307
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package kategory | ||
|
||
typealias Function1F<R> = HK<Function1.F, R> | ||
|
||
fun <P, R> ((P) -> R).k(): Function1<P, R> = | ||
Function1(this) | ||
|
||
@Suppress("UNCHECKED_CAST") | ||
fun <R> Function1F<R>.ev(): FunctionInject<R> = | ||
this as FunctionInject<R> | ||
|
||
// We don't want an inherited class to avoid equivalence issues, so a simple HK wrapper will do | ||
data class Function1<in A, out R>(val f: (A) -> R) : FunctionInject<R>, Function1F<R> { | ||
override fun <P> invokeInject(p: P): R = | ||
f(p as A) | ||
|
||
@Suppress("UNCHECKED_CAST") | ||
operator fun invoke(a: A): R = | ||
f(a) | ||
|
||
class F private constructor() | ||
|
||
companion object { | ||
fun <P> functor() = object : Function1Instances<P> {} | ||
|
||
fun <P> applicative() = object : Function1Instances<P> {} | ||
|
||
fun <P> monad() = object : Function1Instances<P> {} | ||
|
||
fun <P> monadReader() = object : Function1Instances<P> {} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package kategory | ||
|
||
interface FunctionInject<out R> { | ||
fun <P> invokeInject(p: P): R | ||
} | ||
|
||
interface FunctionSurject<in P> { | ||
fun <R> invokeSurject(p: P): R | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package kategory | ||
|
||
interface Function1Instances<P> : | ||
Functor<Function1.F>, | ||
Applicative<Function1.F>, | ||
Monad<Function1.F>, | ||
MonadReader<Function1.F, P> { | ||
|
||
override fun ask(): HK<Function1.F, P> = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what the reason to not return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The compiler doesn't have enough information about the generic F in this context, so it fails. |
||
{ a: P -> a }.k() | ||
|
||
override fun <A> local(f: (P) -> P, fa: HK<Function1.F, A>): Function1<P, A> = | ||
f.andThen { fa.ev().invokeInject(it) }.k() | ||
|
||
override fun <A> pure(a: A): Function1<P, A> = | ||
{ _: P -> a }.k() | ||
|
||
override fun <A, B> map(fa: HK<Function1.F, A>, f: (A) -> B): HK<Function1.F, B> = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return type could be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above, the parameter info isn't available to the compiler. It infers Function1<B, B>. |
||
f.compose { b: B -> fa.ev().invokeInject(b) }.k() | ||
|
||
override fun <A, B> flatMap(fa: HK<Function1.F, A>, f: (A) -> HK<Function1.F, B>): Function1<P, B> = | ||
Function1 { p -> f(fa.ev().invokeInject(p)).ev().invokeInject(p) } | ||
|
||
override fun <A, B> tailRecM(a: A, f: (A) -> HK<Function1.F, Either<A, B>>): Function1<P, B> = | ||
Function1 { p -> | ||
tailrec fun loop(thisA: A): B = | ||
f(thisA).ev().invokeInject(p).fold({ loop(it) }, { it }) | ||
|
||
loop(a) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package kategory | ||
|
||
import io.kotlintest.KTestJUnitRunner | ||
import io.kotlintest.matchers.shouldBe | ||
import org.junit.runner.RunWith | ||
|
||
@RunWith(KTestJUnitRunner::class) | ||
class Function1Test : UnitSpec() { | ||
init { | ||
testLaws(MonadLaws.laws(Function1.monad<Int>(), object : Eq<HK<Function1.F, Int>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this a new instance of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also just realized we are missing |
||
override fun eqv(a: HK<Function1.F, Int>, b: HK<Function1.F, Int>): Boolean = | ||
a.ev().invokeInject(1) == b.ev().invokeInject(1) | ||
})) | ||
|
||
"bla" { | ||
{ a: Int -> a + 1 }.k().invoke(1) | ||
} | ||
|
||
"Function1Monad.binding should for comprehend over all values of multiple Function0" { | ||
val M = Function1.monad<Int>() | ||
M.binding { | ||
val x = Function1 { _: Int -> 1 }.bind() | ||
val y = !Function1 { _: Int -> 2 } | ||
val z = bind { Function1 { _: Int -> 3 } } | ||
yields(x + y + z) | ||
}.ev().invokeInject(0) shouldBe 6 | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we want those Bijections to be public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we have very few private things on the repo. It's all tools, really.