若要判斷 Property 是否包含指定 String,Ramda 並沒有提供類似 propEq()
那樣直接的 Function,但我們可自行組合出 propIncludes()
。
Version
macOS Catalina 10.15.6
Wink-fp 1.23.2
Imperative
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 },
]
// f :: String -> [a] -> [a]
let f = s => a => {
let result = []
for(let x of a)
if (x.title.includes(s))
result.push(x)
return result
}
f('JavaScript')(data) // ?
Imperative 會使用 for
loop,藉由 String.prototype.includes()
判斷指定是否存在,若存在則加入 result
array 回傳。
String.prototype.includes()
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 },
]
// f :: String -> [a] -> [a]
let f = s => a => a.filter(x => x.title.includes(s))
f('JavaScript')(data) // ?
第 7 行
// f :: String -> [a] -> [a]
let f = s => a => a.filter(x => x.title.includes(s))
也可使用 ECMAScript 的 filter()
搭配 includes()
求得。
propSatisfies()
import { propSatisfies, includes, filter } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 },
]
// f :: String -> [a] -> [a]
let f = s => filter(propSatisfies(includes(s), 'title'))
f('JavaScript')(data) // ?
第 9 行
// f :: String -> [a] -> [a]
let f = s => filter(propSatisfies(includes(s), 'title'))
Ramda 亦提供 filter()
與 includes()
,但若要使 filter()
能 point-free,則必須搭配 propSatisfies()
,整體可讀性較差。
propIncludes()
import { includes, filter, curry, useWith, prop, pipe, chain, ap, flip } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 },
]
// propIncludes :: (k, v) -> {k: v} -> Boolean
let propIncludes = (k, v) => o => includes(v, prop(k, o))
// f :: String -> [a] -> [a]
let f = s => filter(propIncludes('title', s))
f('JavaScript')(data) // ?
12 行
// f :: String -> [a] -> [a]
let f = s => filter(propIncludes('title', s))
若能提供類似 propEq()
的 propIncludes()
,則可讀性更高。
第 9 行
// propIncludes :: (k, v) -> {k: v} -> Boolean
let propIncludes = (k, v) => o => includes(v, prop(k, o))
使用用 prop()
取得 value,再使用 includes()
判斷。
Point-free
import { includes, filter, curry, useWith, prop, pipe } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 },
]
// propIncludes :: k -> v -> {k: v} -> Boolean
let propIncludes = useWith(
pipe, [prop, includes]
)
// f :: String -> [a] -> [a]
let f = s => filter(propIncludes('title', s))
f('JavaScript')(data) // ?
第 9 行
// propIncludes :: k -> v -> {k: v} -> Boolean
let propIncludes = useWith(
pipe, [prop, includes]
)
亦可使用 useWith()
使其 point-free。
Wink-fp
import { propSatisfies, includes, filter } from 'ramda'
import { propIncludes } from 'wink-fp'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 },
]
// f :: String -> [a] -> [a]
let f = s => filter(propIncludes('title', s))
f('JavaScript')(data) // ?
Wink-fp 已經內建 propIncludes()
可直接使用。
propIncludes()
k -> v -> {k: v} -> Boolean
判斷指定 String 是否在 Object 的 Property 內
k
:指定 property 的 key
v
:指定 String
{k: v}
:data 為 Object
Boolean
:回傳 Boolean 結果
Function Pipeline
import { propSatisfies, includes, filter, pipe } from 'ramda'
import { propIncludes } from 'wink-fp'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 },
]
// f :: String -> [a]
let f = pipe(
propIncludes('title'),
filter
)
f('JavaScript')(data) // ?
第 10 行
// f :: String -> [a]
let f = pipe(
propIncludes('title'),
filter
)
可使用 pipe()
串起 filter()
與 propIncludes()
使 f()
能 point-free。
Conclusion
- 對於 Object 的 predicate,Ramda 只提供了
propEq()
,但因為 FP 很靈活,因此我們可以自行組合如propGt()
、propGte()
… 等類似 function 方便產生 predicate