반디북
객체에서 함수로
Ch4
우석

연습문제 4.1

fun <T> T.discardUnless(predicate: T.() -> Boolean): T? = if (predicate()) this else null

연습문제 4.2

infix fun <A : Any, B : Any, C : Any> FUN<A, B?>.andUnlessNull(other: FUN<B, C?>): FUN<A, C?> = { a -> this(a)?.let(other) }

연습문제 4.3

fun <A, B, C> ((A, B) -> C).curry(): (A) -> (B) -> C = { a -> { b -> this(a, b) } }
 
// 정답 확인
infix fun <A, B> ((A) -> B).`+++`(a: A): B = this(a)

연습문제 4.4

data class Person(
    val firstName: String,
    val familyName: String
) {
    fun toStringTagMap(): Map<String, StringTag> =
        mapOf(
            "firstName" to StringTag(firstName),
            "familyName" to StringTag(familyName)
        )
}
 
data class EmailTemplate(private val template: String) : (Person) -> String {
    override fun invoke(aPerson: Person): String = renderTemplate(template, aPerson.toStringTagMap())
}
만혁

연습문제 4.1

class DiscardUnlessTest {
 
    @Test
    fun `discard unless`() {
        val itemInProgress = ToDoItem(
            "doing something",
            status = ToDoStatus.InProgress
        )
        val itemBlocked = ToDoItem(
            "must do something",
            status = ToDoStatus.Blocked
        )
 
        expectThat(
            itemInProgress.discardUnless { status == ToDoStatus.InProgress }
        ).isEqualTo(itemInProgress)
 
        expectThat(
            itemBlocked.discardUnless { status == ToDoStatus.InProgress }
        ).isEqualTo(null)
    }
}
 
fun <T> T.discardUnless(predicate: T.() -> Boolean): T? = if (predicate(this)) this else null
 
 
 
data class ToDoItem(
    val name: String,
    val status: ToDoStatus
) {
}
enum class ToDoStatus {
    InProgress,
    Blocked
}

연습문제 4.2

class AndUnlessNullTest {
 
    @Test
    fun `and unless null`() {
 
        val processUnlessNull = ::extractListData andUnlessNull
                ::fetchListContent andUnlessNull
                ::renderHtml andUnlessNull
                ::createResponse
 
        fun fetchList(request: Request): Response = processUnlessNull(request)
            ?: Response(404, "Not found")
 
        val req = Request("GET", URI("http://example.com/zettai/uberto/mylist"), "")
        val resp = fetchList(req)
 
        expectThat(resp) {
            get { status }.isEqualTo(200)
        }
    }
}
 
typealias FUN<A, B> = (A) -> B
infix fun <A : Any, B : Any, C : Any> FUN<A, B?>.andUnlessNull(other: FUN<B, C?>): FUN<A, C?> {
    return { a ->
        val b = this(a)
        if (b == null) {
            null
        } else {
            other(b)
        }
    }
}
 

연습문제 4.4

class EmailTemplateTest {
 
    @Test
    fun `email template test`() {
        val mh = Person("mh", "han")
 
        val templateText = "Hi, "
        val emailTemplate = EmailTemplate(templateText)
        expectThat(emailTemplate(mh)).isEqualTo("Hi, mh")
    }
}
 
 
data class Person(
    val firstName: String,
    val familyName: String
)
 
data class EmailTemplate(private val template: String) : (Person) -> String {
    override fun invoke(aPerson: Person): String {
        return """
            $template, ${aPerson.firstName}
        """.trimIndent()
    }
}