我如何映射&以无点的方式过滤它

时间:2016-10-02 21:21:57

标签: javascript functional-programming pointfree tacit-programming

亲爱的StackOverflowers ......

我有一组帖子:

const posts = [
  { title: 'post1', tags: ['all', 'half', 'third', 'quarter', 'sixth']},
  { title: 'post2', tags: ['all', 'half', 'third', 'quarter', 'sixth']},
  { title: 'post3', tags: ['all', 'half', 'third', 'quarter']},
  { title: 'post4', tags: ['all', 'half', 'third']},
  { title: 'post5', tags: ['all', 'half']},
  { title: 'post6', tags: ['all', 'half']},
  { title: 'post7', tags: ['all']},
  { title: 'post8', tags: ['all']},
  { title: 'post9', tags: ['all']},
  { title: 'post10', tags: ['all']},
  { title: 'post11', tags: ['all']},
  { title: 'post12', tags: ['all']}
];

一组不断增加的效用函数:

const map = f => list => list.map(f);
const filter = f => list => list.filter(f);
const reduce = f => y => xs => xs.reduce((y,x)=> f(y)(x), y);
const pipe = (fn,...fns) => (...args) => fns.reduce( (acc, f) => f(acc), fn(...args));
const comp = (...fns) => pipe(...fns.reverse()); //  const comp = (f, g) => x => f(g(x));
const prop = prop => obj => obj[prop];
const propEq = v => p => obj => prop(p)(obj) === v;
const flatten = reduce(y=> x=> y.concat(Array.isArray(x) ? flatten (x) : x)) ([]);
const unique = list => list.filter((v, i, a) => a.indexOf(v) === i);
const add = a => b => a + b;
const addO = a => b => Object.assign(a, b);
const log = x => console.log(x);

我想将数据按到以下格式:

[
 { title: 'sixth', posts: [array of post objects that all have tag 'sixth'] },
 { title: 'quarter', posts: [array of post objects that all have tag 'quarter'] },
 { title: 'third', posts: [array of post objects that all have tag ’third'] },
 etc...
]

使用无点样式,仅使用可重复使用的紧凑实用程序功能。

我可以从所有帖子中获取唯一标记:

const tagsFor = comp(
  unique,
  flatten,
  map(prop('tags'))
);

tagsFor(posts);

我可以通过map& amp找到如何实现我想要的东西。过滤器:

tagsFor(posts).map(function(tag) {
  return {
    title: tag,
    posts: posts.filter(function(post) {
      return post.tags.some(t => t === tag);
    });
  };
});

我似乎无法以默契的方式实现这一目标。

任何指针都会感激不尽......

2 个答案:

答案 0 :(得分:3)

我可以看到我目前工作中其他一些答案的影响^ _ ^ @Bergi也给你很好的建议。只需继续制作通用程序并将它们组合在一起。

  

我似乎无法以默契的方式实现这一目标。

那么目标不应该是完全无点。很多时候,当你稍后再回来时,你会发现非常奇怪的comp (comp (f))comp (f) (comp (g))这些非常难以理解的东西。

我们仍然可以使用您的代码进行一些改进

这是我们正在改变的代码

// your original code
tagsFor(posts).map(function(tag) {
  return {
    title: tag,
    posts: posts.filter(function(post) {
      return post.tags.some(t => t === tag);
    });
  };
});

这是更新后的代码

// yay
tagsFor(posts).map(makeTag(posts));

// OR
map (makeTag (posts)) (tagsFor (posts));

这是utitilies

const comp = f => g => x => f (g (x));
const apply = f => x => f (x);
const eq = x => y => y === x;
const some = f => xs => xs.some(apply(f));
const filter = f => xs => xs.filter(apply(f));

const postHasTag = tag => comp (some (eq (tag))) (prop ('tags'));

const makeTag = posts => tag => ({
  title: tag,
  posts: filter (postHasTag (tag)) (posts)
});

当然,这只是一种方法。如果这有帮助或者您有任何其他问题,请告诉我们!

“不断增加的效用函数集”

拥有大量实用功能可能会让人感到压力,但你应该留意那些感觉你是在复制行为的人。

以此为例......

const propEq = v => p => obj => prop(p)(obj) === v;

3个参数并不意味着它是一个糟糕的功能,但至少应该让你三思而后行,并确保它们是必需的。请记住,使用更多参数组合函数变得更加困难,因此您也应该仔细考虑参数的顺序。无论如何,这个propEq函数应该为你举起一个红旗。

const eq = x => y => y === x;
const prop = x => y => y[x];
const propEq = p => x => comp (eq(x)) (prop(p))

eq定义为函数后,当您在其他函数中遇到不可分解的===时,您应该可以编写它。这适用于JavaScript中的所有运算符。

作为一个小挑战,请查看您的reducepipecomp,看看您是否可以删除几个积分。如果你遇到困难,请告诉我。

答案 1 :(得分:0)

非常感谢@naomik的重组和@Berghi带领我打破组合逻辑的兔子洞,这就是我想出来的......

首先,tagsFor将一些嵌套数组的所有唯一条目收集到一个数组中,这听起来像是通用功能,而不是特定于任何特定问题的东西,所以我把它重写为:

const collectUniq = (p) => comp( // is this what flatMap does?
  uniq,
  flatten,
  map(prop(p))
);

所以我们有@ naomik的输入:

const hasTag = tag => comp(  // somePropEq?
  some(eq(tag)),
  prop('tags')
);


const makeTag = files => tag => ({
  title: tag,
  posts: filter (hasTag(tag)) (files)
});


const buildTags = comp(
  map(makeTag(posts)),
  collectUniq('tags')
);

任何默契解决方案的问题在于数据(帖子)都隐藏在地图中的makeTag中。

SKI微积分和BCKW逻辑为我们提供了一组有用的组合逻辑函数,我将在这里留下:

const I = x => x;                       // id
const B = f => g => x => f(g(x));       // compose <$> 
const K = x => y => x;                  // pure
const C = f => x => y => f(y)(x);       // flip
const W = f => x => f(x)(x);            // join
const S = f => g => x => f(x)(g(x));    // sub <*>

我们可以将这些别名替换为id,comp,pure,flip等。但在这种情况下,我认为它不会对任何事情有所帮助。

所以,让我们用B(撰写)挖掘帖子:

const buildTags = comp(
  B(map, makeTag)(posts),
  collectUniq('tags')
);

现在我们可以看到它是f(x)(g(x))的形式,其中:f = B(map,makeTag); g = collectUniq(&#39; tags');和x =帖子:

const buildTags = S(B(map)(makeTag))(collectUniq('tags'));

现在它是默认的,陈述性的,容易理解(无论如何我想到)

是的,有人给我一杯啤酒,花了我3天! (哎哟