【发布时间】:2019-10-17 16:53:03
【问题描述】:
我有一个 css 规则对象,它可以有或没有以下属性:
{ 'font-style': '…',
'font-variant': '…',
'font-weight': '…',
'text-decoration': '…',
'vertical-align': '…' }
下一步是构建一个应用于输入的 css 字符串,例如:
style({'text-decoration': 'underline'}, 'foo');
//=> '<span style="text-decoration:underline">foo</span>'
但是如果rules对象不包含以上5个css规则中的任何一个,则输入原样返回:
style({}, 'foo'); //=> 'foo'
如您所见,这不是火箭科学,但必须注意不要应用空的 css 字符串或包含我们不需要的额外内容。
我确实提出了一个使用 ramda.js 的解决方案,直到我决定更深入地研究 Monads 之前,我对此感到非常满意。
我对使用一些 Monadic 原则能够删除的大量代码印象深刻。
const {curry} = require('ramda');
const {Maybe} = require('monet');
const css = (attrs, key) =>
attrs[key] ?
Maybe.of(`${key}:${attrs[key]};`) :
Maybe.of('');
const style = curry((va, td, fw, fv, fs, input) =>
va || td || fw || fv || fs ?
`<span style="${va}${td}${fw}${fv}${fs}">${input}</span>` : input);
module.exports = curry((attrs, input) =>
Maybe.of(input)
.ap(css('font-style', attrs)
.ap(css('font-variant', attrs)
.ap(css('font-weight', attrs)
.ap(css('text-decoration', attrs)
.ap(css('vertical-align', attrs)
.map(style))))))
.some());
我对此很满意,但我不禁想到所有这些嵌套的 ap 都是某种伪装的回调地狱。也许有更好的方法我不知道?
问题:有没有更好的方法来组合多个Maybe monad?
【问题讨论】:
-
这里是应用风格,任何地方都没有单子。回调是源自异步计算的术语。
ap只是一个方法,它有一个包含在应用上下文中的隐式函数,并且需要一堆应用程序。没有回调地狱。可以说方法链避免了嵌套函数组合,也就是说ap(...).ap(...).ap(...)是变相的嵌套函数组合。甚至更好:方法链允许从嵌套函数组合中抽象出来。 -
另一种思考问题的方法是将 Maybe 类型视为
Nothing的空数组或具有一个元素的数组Some值。然后,您可以简单地将所有数组值concat放在一起。这将为您提供与catMaybes相似的结果。 -
我刚刚注意到您实际上也没有使用任何关于
Maybe类型的特定内容。生成的所有Maybe值都使用Maybe.of,因此使用.ap实际上与使用Identity之类的值相同,而不是Maybe。换句话说,您的示例最终只是作为常规函数应用程序。module.exports = attrs => ['font-style', 'font-variant', 'font-weight', 'font-decoration', 'vertical-align'].reduce((fn, k) => fn(css(attrs(k))), style) -
感谢@ScottChristopher。我明白你的意思了。我最终使用了
Maybe.of,尽管我更喜欢使用Just/Nothing子类型。问题是ap不适用于Nothing。 -
@customcommander,这段代码真的运行了吗?我看不出
style应该如何实现style({}, input)。为什么它有6个参数?
标签: ramda.js javascript functional-programming monads ramda.js monetjs