在本系列文中,所有的程式碼以及測試都可以在 should-i-use-fp-ts 找到,今日的範例放在 src/day-11
並且有習題和測試可以讓大家練習。
昨天已經學習到了 getOrElse
, getOrElseW
,但現在還有一種情況是 onSome
需求不需要原始數值,而是需要其他型別,這時候 O.match
完美符合需求。
首先開始實作 match
。
type Match = <A, B>(onNone: () => B, onSome: (x: A) => B) => (x: O.Option<A>) => B;
const match: Match = (onNone, onSome) => x => x._tag === 'None' ? onNone() : onSome(x.value);
可以觀察到 match
和 getOrElse
非常相似,差別只有數值為 Some
時需要再經過一層 onSome
函數來進行處理。接著使用 match
來改寫昨天的範例。
const imperativeMatch = (xs: ReadonlyArray<number>) => {
try {
return `result: ${inverseI(double(headI(xs)))}`; // onSome
} catch {
return 'no value'; // onNone
}
};
// use [1, 2, 3] as an example
const fpMatch = (xs: ReadonlyArray<number>) => pipe(
xs, // [1, 2, 3]
head, // { _tag: 'Some', value: 1 }
O.map(double), // { _tag: 'Some', value: 2 }
O.flatMap(inverse), // { _tag: 'Some', value: 0.5 }
O.match(
() => 'no value', // onNone
v => `result: ${v}`, // onSome
), // 'result: 0.5'
);
同理,match
也會有 onNone
, onSome
想要輸出不同型別的情況,我們接著實作 matchW
type MatchW = <A, B, C>(onNone: () => C, onSome: (x: A) => B) => (x: O.Option<A>) => B | C;
const matchW: MatchW = (onNone, onSome) => x => x._tag === 'None' ? onNone() : onSome(x.value);
一樣以上述的範例改寫。
const imperativeMatchW = (xs: ReadonlyArray<number>) => {
try {
return `result: ${inverseI(double(headI(xs)))}`; // onSome
} catch {
return false; // onNone
}
};
// use [0, 2, 3] as an example
const fpMatchW = (xs: ReadonlyArray<number>) => pipe(
xs, // [0, 2, 3]
head, // { _tag: 'None' }
O.map(double), // { _tag: 'None' }
O.flatMap(inverse), // { _tag: 'None' }
O.matchW(
() => false, // onNone
v => `result: ${v}`, // onSome
), // false
);
今天的主題在 should-i-use-fp-ts src/day-11
有習題和測試可以練習,大家可以嘗試自己能不能寫出自己的 match
和 matchW
。