如何以无点样式映射和过滤它

How do I map & filter this in a point-free style

亲爱的 Whosebugers…

我有一组帖子:

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);

我可以弄清楚如何使用地图和过滤器实现我想要的:

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

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

如有指点,将不胜感激...

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

I just can’t seem to get my head around achieving this in a tacit manner.

好吧,目标不应该是完全无积分。很多时候,你最终会得到非常奇怪的 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));

这是实用程序

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)
});

当然这只是一种方法。让我知道这是否有帮助,或者如果您有任何其他问题!


"Ever-increasing set of utility functions"

拥有大量实用功能可能会让人感到不知所措,但您应该注意一些感觉像是在重复行为的功能。

以这个为例...

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,看看你是否可以删除几个点。如果您遇到困难,请告诉我。

非常感谢@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 等。但在这种情况下,我认为这对 grok 没有任何帮助。

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

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

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

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

现在它是默认的、声明的并且易于理解(无论如何在我看来)

好吧,有人给我拿了瓶花了我 3 天时间的啤酒! (哎哟)