so we get a String (City) then we make a request t...
# arrow
i
so we get a String (City) then we make a request to our DB(with host and port) if our database does not have the city name available we call 3th party app which results us the Weather forcast of that given city // I am trying to transfer some scala code to kotlin, because there are so source examples on how to use tagless final, but thats another convo.
@simon.vergauwen fx still does not work
s
What version of Arrow are you on?
I’m seeing something weird with the API on my branch
Copy code
import arrow.core.Tuple2
import arrow.data.StateT
import arrow.effects.ForIO
import <http://arrow.effects.IO|arrow.effects.IO>
import arrow.effects.extensions.io.applicative.applicative
import arrow.effects.extensions.io.monad.monad

object City
object Forecast
typealias Requests = Map<City, Forecast>
typealias StateReq<A> = StateT<ForIO, Requests, A>

fun fetchForecast(city: City, host: String, port: Int): StateReq<Forecast> =
  TODO()

fun getForecastFromRequests(city: City): StateReq<Forecast?> = StateT(IO.applicative()) { reqs: Requests ->
  IO { Tuple2(reqs, reqs[city]) }
}

fun getForecastFromDB(mForecast: Forecast?, host: String, port: Int): StateReq<Forecast> = StateT(IO.applicative()) { reqs: Requests ->
  IO { Tuple2(reqs, mForecast!!) }
}

fun updateRequests(city: City, forecast: Forecast): StateReq<Unit> = StateT(IO.applicative()) { reqs: Requests ->
  IO { Tuple2(reqs + (city to Forecast), Unit) }
}
Not sure how that much helps already. I think
fx
is only enabled in a commutative way for state on the snapshot atm. cc/ @raulraja
i
I am on 0.9.1
I checked the library, but I did not find it either
Are we generating fx with arrow-meta or not
s
This is the version with
flatMap
anyway
Copy code
fun fetchForecast(city: City, host: String, port: Int): StateReq<Forecast> =
  getForecastFromRequests(city).flatMap(IO.monad()) { mForecast ->
    getForecastFromDB(mForecast, host, port).flatMap(IO.monad()) { forecast ->
      updateRequests(city, forecast)
    }
  }
That should give you an idea how
StateT
works at least
Should give you a good idea what it’d look like using comphresions.
i
mhm
s
I think
ListK
fx has the same restriction atm
i
No fx then
Option to0 right?
Copy code
package arrow.core.extensions.option.fx

@kotlin.jvm.JvmName public fun <A> fx(arg0: suspend arrow.typeclasses.MonadContinuation<arrow.core.ForOption, *>.() -> A): arrow.core.Option<A> { /* compiled code */ }

@kotlin.jvm.JvmName public fun monad(): arrow.typeclasses.Monad<arrow.core.ForOption> { /* compiled code */ }

public fun arrow.core.Option.Companion.fx(): arrow.core.extensions.OptionFx { /* compiled code */ }
s
We’re trying to fix it
i
Ok. Thank you man ! The goal for this example is to have a comparison between tagless and (a primitiv first approach). At least that was the intention of the talk I am translating.
I let you know, when I need your review 😉
s
Copy code
import arrow.core.Tuple2
import arrow.data.StateT
import arrow.data.extensions.statet.fx.fx
import arrow.effects.ForIO
import <http://arrow.effects.IO|arrow.effects.IO>
import arrow.effects.extensions.io.applicative.applicative
import arrow.effects.extensions.io.monad.monad
import arrow.typeclasses.Monad
import arrow.unsafe

object City
object Forecast
typealias Requests = Map<City, Forecast>
typealias StateReq<A> = StateT<ForIO, Requests, A>

val IOMonad: Monad<ForIO> = IO.monad()

fun fetchForecast(city: City, host: String, port: Int): StateReq<Forecast> = unsafe {
  fx<ForIO, Requests, Forecast>(IOMonad) {
    val mForecast = getForecastFromRequests(city).bind()
    val forecast = getForecastFromDB(mForecast, host, port).bind()
    updateRequests(city, forecast).bind()
    forecast
  }
}

fun getForecastFromRequests(city: City): StateReq<Forecast?> = StateT(IO.applicative()) { reqs: Requests ->
  IO { Tuple2(reqs, reqs[city]) }
}

fun getForecastFromDB(mForecast: Forecast?, host: String, port: Int): StateReq<Forecast> = StateT(IO.applicative()) { reqs: Requests ->
  IO { Tuple2(reqs, mForecast!!) }
}

fun updateRequests(city: City, forecast: Forecast): StateReq<Unit> = StateT(IO.applicative()) { reqs: Requests ->
  IO { Tuple2(reqs + (city to Forecast), Unit) }
}
Found it! It resides in
unsafe
atm
I let you know, when I need your review 😉
Please do & share in #arrow-contributors so other can also review 😉
I like mtl and tagless. Always interested in different views and opinions positive or negative.
i
How can I prevent this nesting?
Copy code
val weather: (City, Tuple2<String, Int>) -> IO<Forcast> =
    { city: City, tuple: Tuple2<String, Int> ->
      fx {
        !effect { WeatherClient(tuple.a, tuple.b).forcast(city).getOrDefault { Forcast() } }
      }
    }
  val hottestCity =
    State<Requests, Temperature> { it toT (Request.hottest(it).b.temp) }

  fun askCity() = fx {
    !effect { putStrLn("What is the next city?") }
  }

  fun fetchForecast(city: City, host: String, port: Int): StateReq<Forcast> = unsafe {
    fx(IO.monad()) {
      val mForecast: StateReq<Forcast> = StateT(IO.applicative())
      { reqs: Requests ->
        IO { reqs toT
                  reqs.getOrElse(city,
                    { fx { !effect { weather(city, host toT port).unsafeRunSync()} }.unsafeRunSync() } // call to third-party
                  )
        }
      }
      // still WIP
      val forecast =
        StateT(IO.applicative()) { reqs: Requests ->
          IO { reqs toT mForecast.unsafeFetchWithIO(reqs) }
        }
      //updateRequests(city, forecast)
      //forecast
    }
  }

  fun <A> StateReq<A>.unsafeFetchWithIO(reqs: Requests) =
    runA(IO.monad(), reqs).fix().unsafeRunSync()
in mForcast: unsafeRunSync() . unsafeRunSync()