Imran/Malic
03/31/2019, 8:55 AMJannis
03/31/2019, 12:09 PMJannis
03/31/2019, 12:09 PM@higherkind
sealed class ConsoleF<A> : ConsoleFOf<A> {
/**
* Actions together with a continuation pattern
*/
data class GetLine<A>(val cont: (String) -> A) : ConsoleF<A>()
data class PutStrLn<A>(val str: String, val cont: A) : ConsoleF<A>()
fun <B> map(f: (A) -> B): ConsoleF<B> = when (this) {
is GetLine -> GetLine(cont andThen f)
is PutStrLn -> PutStrLn(str, f(cont))
}
/**
* Inherit from FreeMonad to make life easier later
*/
companion object : FreeMonad<ForConsoleF> {
/**
* Normally this would be defined with @extension, but that only works if its not in the same module
* as @higherkind for the datatype
*/
fun functor() = object : Functor<ForConsoleF> {
override fun <A, B> Kind<ForConsoleF, A>.map(f: (A) -> B): Kind<ForConsoleF, B> = fix().map(f)
}
/**
* Smart constructors to make life easier
*/
fun getLine() = Free.liftF(GetLine(::identity))
fun putStrLn(str: String) = Free.liftF(PutStrLn(str, Unit))
}
}
/**
* Our program using the inherited features from the companion object to get access to binding
*/
val prog = ConsoleF.binding {
!putStrLn("What is your name?")
val (input) = getLine()
!putStrLn("Hello $input")
}.fix()
fun main() {
/**
* This is interpret with recursion-schemes, its in an active pr for recursion-schemes and only here cause I
* needed to test if monadic actions were supported properly so you can ignore this for now :)
*/
prog.interpret(ConsoleF.functor(), { IO.unit }) {
when (val fa = it.fix()) {
is ConsoleF.GetLine -> Eval.later {
IO {
readLine()!!
}.flatMap { fa.cont(it).value() }
}
is ConsoleF.PutStrLn -> Eval.later {
IO { println(fa.str) }.flatMap { fa.cont.value() }
}
}
}.unsafeRunSync()
/**
* Interpret our progam in IO
*/
prog.foldMap(
object : FunctionK<ForConsoleF, ForIO> {
override fun <A> invoke(fa: Kind<ForConsoleF, A>): Kind<ForIO, A> = when (val fa = fa.fix()) {
is ConsoleF.GetLine -> IO {
readLine()!!
}.map(fa.cont)
is ConsoleF.PutStrLn -> IO {
println(fa.str)
fa.cont
}
}
},
IO.monad()
).fix().unsafeRunSync()
}
Imran/Malic
03/31/2019, 12:30 PMkotlin
fun Free<ListK<Int>, Int>.hello() =
transform(
{ it * 2 },
fs = // requirs a FunctionK
)
I actually don’t find anything understandable for FunctionK only this snippet, but I don’t understand it.
kotlin
val cofreeOptionToNel: FunctionK<CofreePartialOf<ForOption>, ForNonEmptyList> = object : FunctionK<CofreePartialOf<ForOption>, ForNonEmptyList> {
override fun <A> invoke(fa: Kind<CofreePartialOf<ForOption>, A>): Kind<ForNonEmptyList, A> =
fa.fix().let { c ->
NonEmptyList.fromListUnsafe(listOf(c.head) + c.tailForced().fix().fold({ listOf<A>() }, { invoke(it).fix().all }))
}
}
Jannis
03/31/2019, 12:36 PMForListK
in your case). Second: To get a Kind<F, A>
into a free monad use Free.liftF
. Lastly a FunctionK
is just a natural transformation of a Kind<F, A>
to a Kind<G, A>
. If you want to keep it as a list just use FunctionK.id()
. The below example really states that using this function one can convert all `Cofree<ForOption, A>`'s to `Nel<A>. What do you intend to use Free
for? If you just want monadic operations over a list then you can simply use the list monad instead.Imran/Malic
03/31/2019, 1:24 PMkotlin
val intListFree = 4.free<ForListK, Int>().hello()
fun Free<ForListK, Int>.hello() =
transform(
{ it * 2 },
fs = FunctionK.id()// requirs a FunctionK
)
compared to this
kotlin
val b = listOf(4).k()
.free()
Which resolves to a Free<Any?, ListK<Int>>Imran/Malic
03/31/2019, 1:29 PMJannis
03/31/2019, 2:06 PMS
is the Functor that Free needs, if you do .free
(which I did not even know exists) it's going to do Free.just
which makes no assumptions about S
. The importance is clear when you want to interpret a Free<S, A>
because you will need a natural transformation over S
. https://typelevel.org/cats/datatypes/freemonad.html does a good job at explaining what Free
can and should be used for, https://medium.com/@olxc/free-monads-explained-pt-1-a5c45fbdac30 is a good read about where free comes from and how it works.
Some vocab before: In arrow a natural transformation is simply a FunctionK and another thing: I hate the cats approach to free monads because they require a monad instance when interpreting which is not necessary at all (but the examples and docs are good)Imran/Malic
03/31/2019, 5:23 PMJannis
03/31/2019, 6:47 PMFunctionK
you need to provide the conversion method. I am a bit confused with what you are trying to do 🙈raulraja
03/31/2019, 7:27 PMraulraja
03/31/2019, 7:28 PMfoldMap
and FunctionK
, that is how Free programs are interepretedJannis
03/31/2019, 8:04 PMImran/Malic
03/31/2019, 8:08 PMraulraja
03/31/2019, 8:32 PMraulraja
03/31/2019, 8:32 PMraulraja
03/31/2019, 8:32 PMraulraja
03/31/2019, 8:34 PMJannis
03/31/2019, 8:35 PMraulraja
03/31/2019, 8:35 PMraulraja
03/31/2019, 8:35 PMraulraja
03/31/2019, 8:35 PMraulraja
03/31/2019, 8:35 PMJannis
03/31/2019, 8:37 PMraulraja
03/31/2019, 8:37 PMJannis
03/31/2019, 8:38 PMraulraja
03/31/2019, 8:38 PMraulraja
03/31/2019, 8:38 PMraulraja
03/31/2019, 8:38 PMraulraja
03/31/2019, 8:38 PMJannis
03/31/2019, 8:38 PMraulraja
03/31/2019, 8:38 PMA
and forces you to cast it in all FunctionKJannis
03/31/2019, 8:40 PMraulraja
03/31/2019, 8:42 PMraulraja
03/31/2019, 8:42 PMraulraja
03/31/2019, 8:43 PMraulraja
03/31/2019, 8:43 PMraulraja
03/31/2019, 8:43 PMImran/Malic
03/31/2019, 8:44 PMraulraja
03/31/2019, 8:44 PMJannis
03/31/2019, 8:44 PMraulraja
03/31/2019, 8:44 PMraulraja
03/31/2019, 8:44 PMraulraja
03/31/2019, 8:45 PMImran/Malic
03/31/2019, 8:46 PMraulraja
03/31/2019, 8:46 PMraulraja
03/31/2019, 8:46 PMJannis
03/31/2019, 8:52 PMJannis
03/31/2019, 8:53 PMraulraja
03/31/2019, 8:59 PMraulraja
03/31/2019, 8:59 PMraulraja
03/31/2019, 9:00 PMfold
in that one is efficient unlike the other one which forces you to nest to the rightJannis
03/31/2019, 9:05 PMbinding
in which I can use any Free<F, A>
, I predefine a typealias = Free<Coproduct...>
and with some annotation magic I get back a binding
of some sort that defines bind for all Free<F, A>
and just injects to Coproduct
and binds with normal bind. I have done that already on one layer (manually) and I think adding layers to it should be possible programmaticallyJannis
03/31/2019, 9:07 PMraulraja
03/31/2019, 9:09 PMraulraja
03/31/2019, 9:10 PMraulraja
03/31/2019, 9:10 PMraulraja
03/31/2019, 9:10 PMraulraja
03/31/2019, 9:11 PMJannis
03/31/2019, 9:17 PMraulraja
03/31/2019, 9:18 PMraulraja
03/31/2019, 9:19 PMraulraja
03/31/2019, 9:19 PMraulraja
03/31/2019, 9:19 PMraulraja
03/31/2019, 9:20 PMraulraja
03/31/2019, 9:20 PMraulraja
03/31/2019, 9:21 PMraulraja
03/31/2019, 9:21 PMJannis
03/31/2019, 9:22 PMraulraja
03/31/2019, 9:22 PMraulraja
03/31/2019, 9:23 PMraiseError
or handleErrorWith
with Free monads?raulraja
03/31/2019, 9:25 PMraulraja
03/31/2019, 9:26 PMraulraja
03/31/2019, 9:26 PMraulraja
03/31/2019, 9:27 PMJannis
03/31/2019, 9:27 PMraulraja
03/31/2019, 9:27 PMhandleErrorWith
?raulraja
03/31/2019, 9:29 PMJannis
03/31/2019, 9:29 PMJannis
03/31/2019, 9:29 PMJannis
03/31/2019, 9:31 PMImran/Malic
03/31/2019, 9:40 PMJannis
03/31/2019, 9:43 PMJannis
04/01/2019, 1:29 PM