DAY 25
0
Software Development

## Bind, Return and Monad laws

``````Ma op (a -> Ma) = Ma
``````

``````Ma op (a -> Mb) = Mb
``````

``````f_op = (Ma, (a -> Mb)) -> Mb
// currying
f_op = Ma -> (a -> Mb) -> Mb
= bind
``````

``````// 左單位元
Id bind (a -> Mb) = a -> Mb
// 右單位元
(a -> Mb) bind Id = a -> Mb
// 結合律
((a -> Mb) bind (b -> Mc)) bind (c -> Md) = (a -> Mb) bind ((b -> Mc) bind (c -> Md))
``````

``````val a = 1
``````

``````// 其中 t 為任意類型
fun <T> return(input: T): F<T>
}
// return in List => listOf
fun <T> return(input: T) = listOf(input)
}
``````

``````f: (a -> Mb)
g: (b -> Mc)
h: (c -> Md)

// 左單位元
(a -> return(a)) bind f = f
// 右單位元
f bind (a -> return(a)) = f
// 結合律
(f bind g) bind h = f bind (g bind h) = f bind g bind h
``````

`````` sealed class Maybe<T>{
class Some<T>(val value: T): Maybe<T>()
class None<T> : Maybe<T>()

fun <R> flatMap(function: (T) -> Maybe<R>): Maybe<R> {
return when(this) {
is Some -> function(this.value)
else -> None()
}
}

companion object {
fun <T> just(value: T?): Maybe<T> {
return if (value == null) {
None()
} else {
Some(value)
}
}
}
}
``````

``````//  try to verify: (a -> return(a)) bind f = f
fun testLeftIdentity() {
// f: toOdd
val toOdd: (Int) -> Maybe<Int> = { x ->
when(x%2) {
0 -> Maybe.None()
else -> Maybe.Some(x)
}
}
val input = 1

// left hand side: (a -> return(a)) bind f
val afterId = Maybe.just(input)
val afterFlatMap = afterId.flatMap(toOdd)
// right hand side: f
val onlyApplyToOdd = toOdd(input)

println(afterFlatMap)
println(onlyApplyToOdd)
}
``````

``````// try to verify: f bind (a -> return(a)) = f
fun testRightIdentity() {
val toOdd: (Int) -> Maybe<Int> = { x ->
when(x%2) {
0 -> Maybe.None()
else -> Maybe.Some(x)
}
}

val input = 1
// left hand side: f bind (a -> return(a))
val afterF = toOdd(input)
val afterFlatMapId = afterF.flatMap(Maybe.Companion::just)
// right hand side: f
val onlyApplyToOdd = toOdd(input)

println(afterFlatMapId)
println(onlyApplyToOdd)
}
``````

``````// try to verify: (f bind g) bind h = f bind (g bind h) = f bind g bind h
fun testRightIdentity(input: Int) {
// f
val toOdd: (Int) -> Maybe<Int> = { x ->
when(x%2) {
0 -> Maybe.None()
else -> Maybe.Some(x)
}
}

// g
val sqrt: (Int) -> Maybe<Int> = { x ->
val result = sqrt(x.toDouble())
when(result) {
Double.NaN -> Maybe.None()
else -> Maybe.Some(result.toInt())
}
}

// h
val toString: (Int) -> Maybe<String> = {x ->
Maybe.Some(x.toString())
}

// (f bind g) bind h
val left = (toOdd(input).flatMap(sqrt)).flatMap(toString)
// f bind (g bind h)
val middle = toOdd(input).flatMap { x: Int -> sqrt(x).flatMap(toString) }
// f bind g bind h
val right = toOdd(input).flatMap(sqrt).flatMap(toString)
}
``````

• 首先是 left 的 `toOdd(input)`，會得到 `Some(9)`，接下來是 `flatMap(sqrt)` ，會得到 `Some(3)` ，最後是 `flatMap(toString)` ，得到的值會是 `Some("3")`
• 接下來換 middle ，第一個一樣是 `toOdd(input)` ，結果也會是 `Some(9)`，接著就是後面的 lambda 了，由於上一個的結果是 `Some(9)` ，所以 lambda 的 x 就會是 9，再來是 `sqrt(x)`，就會得到 `Some(3)`，然後 `Some(3)` 再跟 `flapMap(toString)` 組合，會得到 `Some("3")`，所以這個 `flatMap` 的 lambda 的內容最後會回傳 `Some("3")`，最後的結果也自然而然的是 `Some("3")` 了。

# flatMap 波動拳

``````// 我好奇到底會有多少人會有耐心想看完這個...而且別懷疑，實際上真的會出現這種程式碼
fun flatMapHell(inputMaybe: Maybe<Int>): Maybe<String> {
return inputMaybe.flatMap { x ->
when(x%2) {
0 -> Maybe.None()
else -> Maybe.Some(x)
}.flatMap { y ->
val result = sqrt(y.toDouble())
when(result) {
Double.NaN -> Maybe.None()
else -> Maybe.Some(result.toInt())
}.flatMap {z ->
Maybe.Some(z.toString())
}
}
}
}
``````

``````// 做的事情其實是一樣的，但是可讀性好很多
fun flatMapChaining(inputMaybe: Maybe<Int>): Maybe<String> {
return inputMaybe
.flatMap { x ->
when (x % 2) {
0 -> Maybe.None()
else -> Maybe.Some(x)
}
}.flatMap { y ->
val result = sqrt(y.toDouble())
when (result) {
Double.NaN -> Maybe.None()
else -> Maybe.Some(result.toInt())
}
}.flatMap { z ->
Maybe.Some(z.toString())
}
}
``````