當有 Function 回傳 Either,而後續的 Function 都在 Either 內執行時,卻又有 Function 回傳 Future,這就造成 Either 內有 Future 窘境,實務上該如何處理這種兩層 Monad 呢 ?
Either Future
當沒有輸入任何 ID 時,會顯示 ID is empty
,且不會繼續呼叫 API 查詢價錢。
當輸入 ID 時,就會繼續呼叫 API 查詢價錢。
當 API 回傳 error response 時,則顯示 error message。
<template lang='pug'>
input(v-model='id')
button(@click='onClick') Submit
span {{ price }}
</template>
<script setup>
import { ref } from 'vue'
import { read, write } from 'vue3-fp'
import { pipe, map, path, ifElse, isEmpty, thunkify } from 'ramda'
import { Left, Right, create, env } from 'sanctuary'
import { mapRej, fork, resolve } from 'fluture'
import getPrice from '/src/api/getPrice_'
let { either, I } = create({ checkTypes: false, env })
let id = ref('')
let price = ref('')
let chkEmpty = ifElse(
isEmpty,
thunkify(Left)('ID is empty'),
Right
)
let onClick = pipe(
read(id),
chkEmpty,
map(getPrice),
map(map(path(['data', 'price']))),
map(mapRej(path(['response', 'data', 'error']))),
either(resolve)(I),
fork(write(price))(write(price))
)
</script>
27 行
let onClick = pipe(
read(id),
chkEmpty,
map(getPrice),
map(map(path(['data', 'price']))),
map(mapRej(path(['response', 'data', 'error']))),
either(resolve)(I),
fork(write(price))(write(price))
)
使用 pipe()
組合出 onClick()
:
read(id)
:讀取id
statechkEmpty
:檢查輸入是否為空白,並回傳 Eithermap(getPrice)
:呼叫getPrice()
從 API 查詢 price 並回傳 Futuremap(map(path(['data', 'price'])))
:關鍵在此行,Future 在 Either 內,因此只能map()
先拆第一層 Either,再用map()
拆第二層 Future,所有的 function 都在map(map())
內map(mapRej(path(['response', 'data', 'error'])))
:處理 Rejected Future,在 Rejected Future 內取得response.date.error
either(resolve)(I)
:處理 Left Either,將錯誤訊息包成 Future 回傳fork(write(price))(write(price))
:從 Rejected Future 與 Resolved Future 內取出資料寫入price
state
21 行
let chkEmpty = ifElse(
isEmpty,
thunkify(Left)('ID is empty'),
Right
)
使用 ifElse()
組合出 chkEmpty()
:
isEmpty
:檢查輸入是否為空白thunkify(Left)('ID is empty')
:若輸入為空白,則回傳 Left Either,相當於 ExceptionRight
:正常值則回傳 Right Either
Conclusion
- Future Either 乍聽很嚇人,其實 Either 與 Future 都是 Monad,只要把握使用
map()
與chain()
一層一層處理 Either 與 Future,最後先使用either()
處理 Either,再使用fork()
處理 Future 即可