반디북
객체에서 함수로
Ch7
만혁

연습문제 7.1

data class Holder<T>(private val value: T) {
    fun<U> transform(f: (T) -> U): Holder<U> = Holder(f(value))
 
    fun combine(other: Holder<T>, f: (T, T) -> T): Holder<T> {
        return Holder(f(this.value, other.value))
    }
    
    fun combine2(other: Holder<T>, f: (T, T) -> T): Holder<T> {
        return this.transform { it -> f(it, other.value) }
    }
 
    @Test
    fun test() {
        val hello = Holder("Hello")
        val world = Holder("World")
 
        val result = hello.combine(world) {first, second -> "$first $second"}
        Assertions.assertEquals(result, Holder("Hello World"))
 
    }
}

연습문제 7.3

fun <T> T.asSuccess(): Outcome<Nothing, T> = Success(this)
fun <E : OutcomeError> E.asFailure(): Outcome<E, Nothing> = Failure(this)
 
sealed class Outcome<out E : OutcomeError, out T> {
 
    fun <U> transform(f: (T) -> U): Outcome<E, U> =
        when (this) {
            is Success -> f(value).asSuccess()
            is Failure -> this
        }
 
    fun <F : OutcomeError> transformFailure(f: (E) -> F): Outcome<F, T> =
        when (this) {
            is Success -> this
            is Failure -> f(error).asFailure()
        }
}

연습문제 7.4

fun <T> tryAndCatch(f: () -> T): Outcome<ThrowableError, T> {
    return try {
        f().asSuccess()
    } catch (t: Throwable) {
        ThrowableError(t).asFailure()
    }
}
우석

연습문제 7.1

fun combine(other: Holder<T>, f: (T, T) -> T): Holder<T> =
    transform { v -> f(v, other.value) }

연습문제 7.2

@Test
fun 펑터는_항등사상을_보존해야_한다() {
    repeat(1000) {
        val randomNumber = random.nextInt().asSuccess()
        val sut = randomNumber.transform(::identity)
 
        expectThat(randomNumber).isEqualTo(sut)
    }
 
}
 
@Test
fun 펑터는_사상의_합성을_보존해야_한다() {
    repeat(1000) {
        val randomString = getRandomString(random.nextInt(1000)).asSuccess()
        val o1 = randomString.transform {
            v -> v.length
        }.transform {
            v -> v + 1
        }
 
        val lengthPlusOne = String::length andThen Int::inc
        val o2 = randomString.transform(lengthPlusOne)
 
        expectThat(o1).isEqualTo(o2)
    }
}
 
fun getRandomString(length: Int): String {
    val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
    return (1..length)
        .map { allowedChars.random() }
        .joinToString("")
}

연습문제 7.3

fun <F : OutcomeError> transformFailure(f: (E) -> F): Outcome<F, T> =
    when (this) {
        is Failure -> f(this.error).asFailure()
        is Success -> this
    }

연습문제 7.4

fun <T> tryAndCatch(block: () -> T): Outcome<ThrowableError, T> {
   return try {
       block().asSuccess()
   } catch (t: Throwable) {
       ThrowableError(t).asFailure()
   }
}