Skip to content

Instantly share code, notes, and snippets.

@raulraja
Last active October 30, 2021 16:30
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save raulraja/97e2d5bf60e9d96680cf1fddcc90ee67 to your computer and use it in GitHub Desktop.
Save raulraja/97e2d5bf60e9d96680cf1fddcc90ee67 to your computer and use it in GitHub Desktop.
Simple Kotlin DI
package com.fortyseven.fptraining
import arrow.core.Either
import arrow.core.right
import arrow.effects.IO
import arrow.effects.extensions.io.fx.fx
data class Account(val balance: Int)
data class AccountEntity(val balance: Int)
/** User algebras **/
interface UI {
fun present(): IO<Unit>
}
interface Domain {
fun getProcessedAccount(): IO<Account>
}
interface Data {
fun fetchAccount(): IO<AccountEntity>
}
/** interpreters */
object InMemoryData : Data {
fun retrofit(callback: (Either<Throwable, AccountEntity>) -> Unit): Unit =
callback(AccountEntity(100).right())
override fun fetchAccount(): IO<AccountEntity> =
IO.async { _, callback ->
retrofit(callback)
}
}
class DefaultDomain(val data: Data) : Domain {
override fun getProcessedAccount(): IO<Account> =
data.fetchAccount().map { Account(it.balance) }
}
class DefaultUI(val domain: Domain) : UI {
override fun present(): IO<Unit> =
fx {
val account = domain.getProcessedAccount().bind()
!effect { println(account) }
}
}
class Module(
data: Data = InMemoryData,
domain: Domain = DefaultDomain(data),
val ui: UI = DefaultUI(domain)
) {
companion object {
val defaultInstance = Module()
}
}
fun main() {
Module.defaultInstance.ui.present().unsafeRunSync()
}
package com.fortyseven.fptraining
import arrow.core.Either
import arrow.core.right
import arrow.effects.IO
import arrow.effects.extensions.io.fx.fx
data class Account(val balance: Int)
data class AccountEntity(val balance: Int)
interface Data {
fun fetchAccount(): IO<AccountEntity>
}
class InMemoryData: Data {
fun retrofit(callback: (Either<Throwable, AccountEntity>) -> Unit): Unit =
callback(AccountEntity(100).right())
override fun fetchAccount(): IO<AccountEntity> =
IO.async { _, callback ->
retrofit(callback)
}
}
interface Domain {
fun <R> R.getProcessedAccount(): IO<Account> where R: Data
}
class DefaultDomain : Domain {
override fun <R> R.getProcessedAccount(): IO<Account> where R: Data =
fetchAccount().map { Account(it.balance) }
}
interface UI {
fun <R> R.present(): IO<Unit> where R: Domain, R: Data
}
class DefaultUI : UI {
override fun <R> R.present(): IO<Unit> where R: Domain, R: Data =
fx {
val account = getProcessedAccount().bind()
!effect { println(account) }
}
}
class Module(
data: Data = InMemoryData(),
domain: Domain = DefaultDomain(),
val ui: UI = DefaultUI()
) : Data by data, UI by ui, Domain by domain {
companion object {
val defaultInstance = Module()
}
}
fun main() {
with(Module.defaultInstance) {
present().unsafeRunSync()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment