package com.test.arrow.monad.monad_error import arrow.Kind import arrow.core.Either import arrow.core.extensions.either.monadError.monadError import arrow.core.fix import arrow.typeclasses.MonadError object Nuke object Target object Impacted sealed class NukeError { object SystemOffline : NukeError() object RotationNeedsOil : NukeError() data class MissedByMeters(val meters: Int) : NukeError() } typealias SystemOffline = NukeError.SystemOffline typealias RotationNeedsOil = NukeError.RotationNeedsOil typealias MissedByMeters = NukeError.MissedByMeters typealias Arm = (MonadError) -> Kind typealias Aim = (MonadError) -> Kind typealias Launch = (MonadError, Target, Nuke) -> Kind fun attack(ME: MonadError, arm: Arm, aim: Aim, launch: Launch): Kind = ME.fx.monad { val (nuke) = arm(ME) val (target) = aim(ME) val (impact) = launch(ME, target, nuke) impact } fun arm(ME: MonadError): Kind = ME.just(Nuke) fun aim(ME: MonadError): Kind = ME.just(Target) fun launch(ME: MonadError, target: Target, nuke: Nuke) = ME.just(Impacted) fun armFailed(ME: MonadError): Kind = ME.raiseError(SystemOffline) fun aimFailed(ME: MonadError): Kind = ME.raiseError(RotationNeedsOil) fun launchFailed(ME: MonadError, target: Target, nuke: Nuke): Kind = ME.raiseError(MissedByMeters(5)) fun runOnEitherSuccess(): Either { return attack(Either.monadError(), ::arm, ::aim, ::launch).fix() } fun runOnEitherFail1(): Either { return attack(Either.monadError(), ::armFailed, ::aim, ::launch).fix() } fun runOnEitherFail2(): Either { return attack(Either.monadError(), ::arm, ::aimFailed, ::launch).fix() } fun runOnEitherFail3(): Either { return attack(Either.monadError(), ::arm, ::aim, ::launchFailed).fix() } fun main() { println(runOnEitherSuccess()) println(runOnEitherFail1()) println(runOnEitherFail2()) println(runOnEitherFail3()) } /* fun runOnOption(): Option { val me: OptionMonadError = Option.monadError() return attack(me, ::arm, ::aim, ::launch).fix() } fun runOnIO(): IO { val me: IOMonadError = IO.monadError() return attack(me, ::arm, ::aim, ::launch).fix() } */