當有 Function 回傳 Maybe,而後續的 Function 都在 Maybe 內執行時,卻又有 Function 回傳 Future,這就造成 Maybe 內有 Future 窘境,實務上該如何處理這種兩層 Monad 呢 ?
Version
Vue 3.0.11
Sanctuary 3.1.0
Fluture 14.0.0
Future Maybe
當輸入書名找不到時,會顯示 N/A
。
當找到書名時,就會繼續呼叫 API 查詢價錢。
當 API 回傳 error response 時,則顯示 error message。
<template lang='pug'>
input(v-model='title')
button(@click='onClick') Submit
span {{ price }}
</template>
<script setup>
import { ref } from 'vue'
import { read, write } from 'vue3-fp'
import { pipe, propEq, map, path } from 'ramda'
import { create, env, prop, flip, find } from 'sanctuary'
import { mapRej, fork, resolve } from 'fluture'
import getPrice from '/src/api/getPrice_'
let { maybe, I } = create({ checkTypes: false, env })
let data = [
{ id: 1, title: 'FP in JavaScript' },
{ id: 2, title: 'Elm in Action' },
{ id: 3, title: 'Speaking JavaScript' }
]
let title = ref('')
let price = ref('')
let onClick = pipe(
read(title),
propEq('title'),
flip(find)(data),
map(prop('id')),
map(getPrice),
map(map(path(['data', 'price']))),
map(mapRej(path(['response', 'data', 'error']))),
maybe(resolve('N/A'))(I),
fork(write(price))(write(price))
)
</script>
18 行
let data = [
{ id: 1, title: 'FP in JavaScript' },
{ id: 2, title: 'Elm in Action' },
{ id: 3, title: 'Speaking JavaScript' }
]
- 使用
find()
查詢title
,無論是否存在都會回傳 Maybe - 後續的處理也都會在 Maybe 內,包含呼叫 API 也會在 Maybe 內
- API 會回傳 Future,這就造成 Future 在 Maybe 內,也就是 Future Maybe
該如何處理 Future Maybe 這種兩層 Monad 呢 ?
27 行
let onClick = pipe(
read(title),
propEq('title'),
flip(find)(data),
map(prop('id')),
map(getPrice),
map(map(path(['data', 'price']))),
map(mapRej(path(['response', 'data', 'error']))),
maybe(resolve('N/A'))(I),
fork(write(price))(write(price))
)
使用 pipe()
組合 onClick()
:
read(title)
:讀取title
statepropEq('title')
:組合find()
所需要的 callbackflip(find)(data)
:與Array.prototype.find()
的差異是無論找不找得到都會傳 Maybe,因此不用擔心undefined
問題map(prop('id'))
::在 Maybe 內讀取出id
propertymap(getPrice)
:呼叫getPrice()
從 API 查詢 price 並會回傳 Futuremap(map(path(['data', 'price'])))
:關鍵在此行,Future 在 Maybe 內,因此只能map()
先拆第一層 Maybe,再用map()
拆第二層 Future,所有的 function 都在map(map())
內maybe(resolve('N/A'))(I)
:處理 Nothing Maybe,將N/A
包成 Future 回傳fork(write(price))(write(price))
:從 Rejected Future 與 Resolved Future 內取出資料寫入price
state
Conclusion
- Future Maybe 乍聽很嚇人,其實 Maybe 與 Future 都是 Monad,只要把握使用
map()
與chain()
一層一層處理 Maybe 與 Future,最後先使用maybe()
處理 Maybe,再使用fork()
處理 Future 即可