如何将多个参数传入Ramda撰写链?

时间:2016-12-31 02:22:10

标签: functional-programming function-composition ramda.js

以下是我试图组成单个端点字符串的四个函数:

const endpoint = str => `${str}` || 'default'
const protocol = str => `https://${str}`
const params = str => `${str}?sort=desc&part=true&`
const query = str => `${str}query={ some:'value', another:'value'}`

let finalEndpoint = R.compose(query, params, protocol, endpoint)

var result = finalEndpoint('api.content.io')

这个组合工作并返回我想要的结果:

https://api.content.io?sort=desc&part=true&query={ some:'value', another:'value'}

但请注意我的函数体中paramsquery硬编码值。我看到只有一个值超过了此R.compose链中的值。

如何以及在何处将参数传递给参数和查询参数?

更新:

我所做的是对这些功能进行了调整:

var R = require('ramda');

const endpoint = str => `${str}` || 'default'
const protocol = str => `https://${str}`
const setParams = R.curry ( (str, params) => `${str}?${params}` )
const setQuery = R.curry ( (str, query) => `${str}&query=${JSON.stringify(query)}` )

然后

let finalEndpoint = R.compose(protocol, endpoint)

var result = setQuery(setParams(finalEndpoint('api.content.io'), 'sort=desc&part=true'), { some:'value', another:'value'})

console.log(result);

但是获得result的最终调用仍然看起来非常黑,而且不够优雅。有没有办法改善这个?

3 个答案:

答案 0 :(得分:6)

  

如何以及在何处将参数传递给参数和查询参数?

老实说,你没有,不是在你用Ramda或类似的库构建composepipe管道时。

Ramda(免责声明:我是其中一位作者)允许第一个函数接收多个参数 - 其他一些函数执行,有些则没有 - 但后续函数只接收先前调用的结果。 Sanctuarymeld中有一个函数可能对此有所帮助,但它确实有一个相当复杂的API。

但是,我真的不明白为什么你首先以这种方式构建这个功能。这些中间函数是否实际可重用,或者您是否按规范构建它们?我问的原因是,这似乎是同一个想法的一个更合理的版本:

const finalEndpoint = useWith( 
  (endpoint, params, query) =>`https://${endpoint}?${params}&query=${query}`, [
    endpoint => endpoint || 'default', 
    pipe(toPairs, map(join('=')), join('&')), 
    pipe(JSON.stringify, encodeURIComponent)
  ]
);

finalEndpoint(
  'api.content.io', 
  {sort: 'desc', part: true},
  {some:'value', another:'value'}
);
//=> "https://api.content.io?sort=desc&part=true&query=%7B%22some%22%3A%22value%22%2C%22another%22%3A%22value%22%7D"

我真的不知道你对最后一个参数的要求。没有encodeUriComponent,我看起来很奇怪,但也许你不需要它。我还对第二个参数采取了自由,假设您更喜欢API中的实际数据到封装该数据的字符串。但是,如果您希望传递'sort=desc&part=true',请将pipe(toPairs, map(join('=')), join('&'))替换为identity

由于整个事情远非无点,我没有使用第一个函数的无点版本,可能是or(__, 'default'),因为我认为它更具可读性。

<强>更新

您可以在 Ramda REPL 上看到此版本,该版本会在tap处添加一些console.log语句。

这确实为Ramda提出了一个有趣的问题。如果这些中间函数确实是可取的,那么Ramda无法将它们组合起来。显然Ramda可以提供类似meld的东西,但是有中间地位吗?我想知道是否有一个有用的功能(当然是咖喱),我们应该包括像

这样的功能
someFunc([f0], [a0]); //=> f0(a0)
someFunc([f0, f1], [a0, a1]); //=> f1(f0(a0), a1)
someFunc([f0, f1, f2], [a0, a1, a2]); //=> f2(f1(f0(a0), a1), a2)
someFunc([f0, f1, f2, f3], [a0, a1, a2, a3]); //=> f3(f2(f1(f0(a0), a1), a2), a3)
// ...

有一些严重的反对意见:如果列表长度不同会怎么样?为什么初始调用是一元的,我们应该通过向函数添加单独的累加器参数来解决这个问题吗?尽管如此,这是一个有趣的功能,我可能会提出它来讨论Ramda主板。

答案 1 :(得分:1)

我为这种情况写了a little helper function

就像compose,但是其余的参数也传入。第一个参数是前一个函数的返回值。其余的参数保持不变。

有了它,您可以按如下方式重写代码:

const compound = require('compound-util')

const endpoint = str => `${str}` || 'default'
const protocol = str => `https://${str}`
const params = (str, { params }) => `${str}?${params}`
const query = (str, { query }) => `${str}query=${query}`

const finalEndpoint = compound(query, params, protocol, endpoint)

const result = finalEndpoint('api.content.io', {
  params: 'sort=desc&part=true&',
  query: JSON.stringify({ some:'value', another:'value'})
})

答案 2 :(得分:0)

如果你有params并查询curried函数,那么你可以:

编辑:包含所有花里胡哨的代码,需要更改参数顺序或使用R.__和字符串化对象

const endpoint = R.curry( str => `${str}` || 'default' )
const protocol = R.curry( str => `https://${str}` )
const params = R.curry( (p, str) => `${str}?${p}` )
const query = R.curry( (q, str) => `${str}&query=${q}` )

let finalEndpoint =
    R.compose(
        query(JSON.stringify({ some:'value', another:'value' })),
        params('sort=desc&part=true'),
        protocol,
        endpoint
    )
var result = finalEndpoint('api.content.io')
console.log(result)