惯用Ramda用于生成更高阶函数?

时间:2016-02-17 03:37:13

标签: javascript functional-programming higher-order-functions currying ramda.js

我的目标是创建一个自定义地图函数,首先需要过滤列表以保留,例如,在每个项目上调用提供的函数之前,只保留偶数项目。我确实需要咖喱功能,第一个参数是函数,而不是列表。我相信签名看起来像这样:(a -> b) -> [a] -> [b]

当然有很多方法可以做到这一点。这是我的第一次尝试。

var isEven = x => x % 2 === 0;

var filterEvensMap = R.curry((fn, items) => R.map(fn, R.filter(isEven, items)));

filterEvensMap(R.negate, [1,2,3,4]); // [-2, -4]

但是,由于上面使用了带有fnitems"胶水参数的匿名函数",我不确定这是Ramda的用途使用。

下面我提到了另一种方法。这似乎更符合Ramda的精神,但我不确定我是否会使事情复杂化。

var filterEvensMap = R.compose(
  R.flip,
  R.uncurryN(2)
)(R.compose(
  R.flip(R.map),
  R.filter(isEven)
));

我是否因为多个组合和uncurryN过于复杂?有没有更惯用的方法来实现这一目标?根据您的经验,这有关系吗?

提前致谢。

1 个答案:

答案 0 :(得分:2)

如果您发现Haskell签名有用,您可能会发现此point-free generatorsource)也很有用。如果要简化表达式,可以输入与JS代码等效的Haskell:

filterEvensMap = (. filter isEven) . map

它会给你一个无点的等价物:

var filterEvensMap = R.curry(R.compose(R.compose(R.filter(isEven)), R.map))

然后使用Ramda转换回JS:

    // imports
var {DragSource, DragDropContext} = ReactDnD;

var knightSource = {
    beginDrag: function (props) {
        return {};
    }
};

function collect(connect, monitor) {
    return {
        connectDragSource: connect.dragSource(),
        isDragging: monitor.isDragging()
    }
}

var Knight = DragSource("knight", knightSource, collect)(React.createClass({
    render() {
        var style = {
            cursor: 'move',
            fontSize: 25
        }
        return(
            <div style={style}>♘</div>
        );
    }
}));


var Board = DragDropContext(HTML5Backend)(React.createClass({
    render() {
        var style = {
            width: '500px',
            height: '500px',
            border: '1px solid black',
            boxShadow: '4px 2px 2px black'
        }
        return (
            <div style={style}>
                <Knight/>
            </div>
        );
    }
}));

ReactDOM.render(
    <Board/>,
    document.getElementById('ex13')
);
  

根据您的经验,这有关系吗?

我会使用最易读的表达式,在这种情况下可能是原始表达式。无点是有趣的,可以在某些地方增加清晰度,但它也会大大降低可读性,或者至少是理解水平。