内容简介:在 Elixir 的部落格發現一個很帥的VS Code 1.32.3Quokka 1.0.200
在 Elixir 的部落格發現一個很帥的 wrap() Operator,除了可以將 Array 攤平,還可以讓 null 優雅的消失,特別將其 Porting 到 Ramda。
Version
VS Code 1.32.3
Quokka 1.0.200
Ramda 0.26.1
wrap()
import { pipe, filter, identity, unnest, of } from 'ramda';
// wrap :: a -> [a]
const wrap = pipe(
of,
unnest,
filter(identity)
);
console.log(wrap(1));
console.log(wrap(null));
console.log(wrap([2, 3]));
wrap() 的功能如下:
null
of() 先將 value 變成 array,這使得 wrap(1) 成為 [1] 。
但 wrap([2, 3]) 則會變成 [[2, 3]] ,顯然多了一層 array,所以還要配合 unnest() 攤平一層,但這對 wrap(1) 沒有影響,因為只有一層的 array 對 unnest() 無效。
filter(identity) 則是針對 wrap(null) ,因為 null !== null ,因此會被 filter() 濾掉,也就是 null 不會新增進 array,但為其他 primitive value 與 array 則毫無影響。
wrap() 有什麼威力呢 ? 讓我們繼續看下去。
Imperative
const data = [
{ teacher: { name: 'John', age: 40 } },
{ assistant: null },
{ students: [
{ name: 'Amber', age: 20 },
{ name: 'William', age: 22 }
] }
];
// getResult :: [a] -> [b]
const getResult = data => {
const result = [];
for (let obj of data) {
for (let obj2 of Object.values(obj)) {
if (obj2 !== null && !Array.isArray(obj2)) {
result.push(obj2);
}
if (Array.isArray(obj2)) {
for (let obj3 of Object.values(obj2)) {
if (obj3 !== null) {
result.push(obj3);
}
}
}
}
}
return result;
};
console.dir(getResult(data));
data 為 array,每個 object 的 key 並不相同,各為 teacher 、 assistant 與 students 。且自個 value 亦為 object、null 與 array,除了 key 不同,value 格式也不同。
[ { name: 'John', age: 40 },
{ name: 'Amber', age: 20 },
{ name: 'William', age: 22 } ]
若我們希望結果為一層 array,且僅包含 object,並不包含 null 。
for (let obj of data) {
}
若使用 Imperative,由於 data 為 array,所以要先使用 for loop 展開。
for (let obj2 of Object.values(obj)) {
if (obj2 !== null && !Array.isArray(obj2)) {
result.push(obj2);
}
}
由於需求不顯示 null ,因此要使用 if 先過濾 null 。
array 也必須排除,因為 array 稍後要特別處理。
if (Array.isArray(obj2)) {
for (let obj3 of Object.values(obj2)) {
if (obj3 !== null) {
result.push(obj3);
}
}
}
由於 students 為 array,因此又要使用 for loop 加以展開。
可以發現 Imperative 寫法,需動用三層 for loop ,且還必須用 if 判斷 null 與 array 另外處理, 可讀性很差。
chain()
import { pipe, filter, identity, unnest, of, values, chain } from 'ramda';
const data = [
{ teacher: { name: 'John', age: 40 } },
{ assistant: null },
{ students: [
{ name: 'Amber', age: 20 },
{ name: 'William', age: 22 }
] }
];
// wrap :: a -> [a]
const wrap = pipe(
of,
unnest,
filter(identity)
);
// getResult :: [a] -> [b]
const getResult = pipe(
chain(x => wrap(values(x))),
unnest
);
console.dir(getResult(data));
若使用了 wrap() ,則 null 不會進 array,會優雅的消失,因此不用特別判斷。
chain() 雖然號稱是 flatMap() ,但實際上是 pipe(map, unnest) ,只能使 array 攤平一層,這對 teacher 是有用的,但 students 還有一層,因此必須再使用 pipe(chian, unnest) 繼續攤平。
可以發現使用了 wrap() 之後,除了看不到 for loop 外,連 null 與 array 都不用判斷,非常優雅
Point-free
import { pipe, filter, identity, unnest, of, values, chain, compose } from 'ramda';
const data = [
{ teacher: { name: 'John', age: 40 } },
{ assistant: null },
{ students: [
{ name: 'Amber', age: 20 },
{ name: 'William', age: 22 }
] }
];
// wrap :: a -> [a]
const wrap = pipe(
of,
unnest,
filter(identity)
);
// getResult :: [a] -> [b]
const getResult = pipe(
chain(compose(wrap, values)),
unnest
);
console.dir(getResult(data));
其實之前的寫法,可讀性已經很高,若想將 chian() 的 callback 進一步 Point-free,可使用 compose() 將 wrap() 與 values() 加以組合。
實務上對架構會使用 pipe() 顯示流程,callback 會使用 compose() 表示組合
Composition
import { pipe, filter, identity, unnest, of, values, chain } from 'ramda';
const data = [
{ teacher: { name: 'John', age: 40 } },
{ assistant: null },
{ students: [
{ name: 'Amber', age: 20 },
{ name: 'William', age: 22 }
] }
];
// wrap :: a -> [a]
const wrap = pipe(
of,
unnest,
filter(identity)
);
// getResult :: [a] -> [b]
const getResult = pipe(
chain(values),
chain(wrap),
unnest
);
console.dir(getResult(data));
chain() 支援的 data 為 Chain 型別,而 Chain 型別一定也是 Functor 型別。
其實 array 既是 Functor 也是 Chain ,而 Functor 的基本特性就是支援數學的 identity 與 composition。
Composition 就是 chain(x => f(g(x))) 等於 pipe(chain(x => g(x)), chain(x => f(x)) ,因此可將 compose() 拆開,改成兩次 chain() 。
要不要將 compose() 拆開改成 pipe() 則見仁見智,最少這是 Functor 的基本特性:composition,可以等效替換,可讓整個流程只使用 pipe() ,讓 chain() 只有一層
Conclusion
- Elixir 的
wrap()理念很好,除了讓 array 自動減少一層外,還可讓null優雅的消失,他山之石可以攻錯,我們也可以在 Ramda 實現wrap() -
chain()雖然號稱是flatMap(),其實是compose(unnest, map),只能攤平一層 array -
chain()雖然支援的是Chain,而Chain就是Functor,且 array 既是Functor也是Chain,因此也支援 Functor 的基本特性:Composition,因此可將compose解開改用pipe
Reference
以上所述就是小编给大家介绍的《如何使用 Ramda 實作 wrap() ?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- RecyclerView使用指南(一)—— 基本使用
- 如何使用Meteorjs使用URL参数
- 使用 defer 还是不使用 defer?
- 使用 Typescript 加强 Vuex 使用体验
- [译] 何时使用 Rust?何时使用 Go?
- UDP协议的正确使用场合(谨慎使用)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java Message Service API Tutorial and Reference
Hapner, Mark; Burridge, Rich; Sharma, Rahul / 2002-2 / $ 56.49
Java Message Service (JMS) represents a powerful solution for communicating between Java enterprise applications, software components, and legacy systems. In this authoritative tutorial and comprehens......一起来看看 《Java Message Service API Tutorial and Reference》 这本书的介绍吧!
MD5 加密
MD5 加密工具
XML、JSON 在线转换
在线XML、JSON转换工具