raulraja
10/07/2017, 10:46 PMOption.monad().binding {
val a = Option(1).bind()
val b = Option(a + 1).bind()
yields(b)
}
//Option(2)
binding
is a Continuation and bind
is implemented as a COROUTINE_SUSPENDED
function that unwinds flatMap
calls until the entire binding is completed as shown here https://github.com/kategory/kategory/blob/master/kategory-core/src/main/kotlin/kategory/typeclasses/MonadContinuations.kt#L53-L61
For this to work we are resorting to a dirty hack which is making the private label
and completion
properties visible so we can mutate them accordingly. https://github.com/kategory/kategory/blob/master/kategory-core/src/main/kotlin/kategory/typeclasses/ContinuationUtils.kt
Do you know if there is a better way of doing this? Thanks in advance for any pointers in the right direction 🙂elizarov
10/08/2017, 9:38 PMraulraja
10/08/2017, 10:41 PMA Continuation<T> implemented by a state machine modifies its label, so that we cannot run one continuation several times from the same label. The workaround I used: back up the label through reflection before the resume call and restore it once the call returns.
elizarov
10/09/2017, 6:29 AMfor (x in m)
instead of val x = bind(m)
? The former avoids the need to save/load state altogether, as the compiler becomes responsible for it.raulraja
10/09/2017, 7:25 PMfor(_ in _)
support multiple binds or are there plans to do that? Something along the lines of :
for (x in listOf(1); y in listOf(x + 1)) yield y // List(2)
for
is just looking for iterator()
I can potentially implement monadic bind in terms of hasNext()
and next()
in monads but if a single bind is supported it would result in a nested chain of for loops and I have no way to return the resulting values since for
is not an expression but a control structure.flatMap(f: (A) -> F<B>)
in the same way it supports iterator()
so any structural evidence of having flatMap
on a type allows for comprehensions enabling List generators, etc?elizarov
10/10/2017, 9:39 AMfor
are done like this: for (x in listOf(1)) for (y in listOf(x + 1)) yield(y)
Iterator
interface. It works by convention. It can be any interface that has operator fun iterator(): SomeResult
where SomeResult
has operator fun hasNext(): Boolean
and operator fun next(): T
for(x in channel)
where channel
is neither Collection
, neither Sequence
, nor Iterable
at allraulraja
10/10/2017, 6:10 PMpakoito
10/10/2017, 8:26 PMraulraja
10/10/2017, 8:29 PMyield
it becomes oneoperator fun <A> Option<A>.iterator(): OptionIterator<A> = OptionIterator(this)
class OptionIterator<A>(val fa: Option<A>) {
operator fun hasNext(): Boolean = fa.fold({false}, {true})
operator fun next(): A = fa.getOrElse { throw IllegalStateException("next() invoked on empty Option") }
}
How can I implement this function using `for`:
fun compute(): Option<Int> =
for(x in Option(1))
for(y in Option(x + 1))
yield(y)
compute() // Option(2)
yield
requires to be invoked in a coroutine. Do I need to resort to mutation to be able to return something or does yield
lifts values back into the context of Option
in this case?elizarov
10/10/2017, 9:49 PMraulraja
10/10/2017, 9:57 PMyield(y)
in that case match the return type expected by the option builder? If say the option builder expects back Option<Int>
for example would yield
satisfy that or do builders always need to return Unit
?