内容简介:在 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协议的正确使用场合(谨慎使用)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
jQuery基础教程
Jonathan Chaffer、Karl Swedberg / 李松峰、卢玉平 / 人民邮电出版社 / 2009-11 / 49.00元
《jQuery基础教程(第2版)》作为《jQuery基础教程》的升级版,涵盖了jQuery 1.3的全部新特性,特别是新增了介绍jQuery UI(jQuery官方用户界面插件库)的内容。《jQuery基础教程(第2版)》前6章以通俗易懂的方式介绍了jQuery的基本概念,主要包括jQuery的选择符、事件、效果、DOM操作、AJAX支持等。随后3章从理论到实践,通过表格操作、构建功能型表单、实现......一起来看看 《jQuery基础教程》 这本书的介绍吧!