Compute intersections of all combinations of vectors in a list of vectors in R
Your approach seems reasonable, but there are some simplifications you can make.

First, your construction of name is needlessly complex.  This works just as well:

name &lt;- paste(names(l)[indices], collapse="_")


Second, you can call unique on each element of l at the outset which eliminates the need to specify an init value to Reduce (and thus reducing all the calculations by one call to intersect). It also shortens the arguments to intersect since duplicates have already been eliminated.

l &lt;- lapply(l, unique)


These two give a function

overlap &lt;- function(l) {
  results &lt;- list()
  # Remove duplicates within each entry of l
  l &lt;- lapply(l, unique)

  # combinations of m elements of list l
  for (m in seq(along=l)) {

    # generate and iterate through combinations of length m
    for (indices in combn(seq(length(l)), m, simplify=FALSE)) {

      # make name by concatenating the names of the elements
      # of l that we're intersecting
      name &lt;- paste(names(l)[indices], collapse="_")

      results[[name]] &lt;- Reduce(intersect, l[indices])
    }
  }
  results
}


Further elimination of duplicate work would involve recognizing that higher order interactions, as you are determining them now, are repeating the intersections of the lower orders (that is foo_bar_bat first intersects foo and bar and then intersects that with bat, but the intersection of foo and bar was already determined). And "first" order interactions are just the arguments passed through unique (as they were simplified in the previous iteration).

overlap &lt;- function(l) {
  results &lt;- lapply(l, unique)

  # combinations of m elements of list l
  for (m in seq(along=l)[-1]) {

    # generate and iterate through combinations of length m
    for (indices in combn(seq(length(l)), m, simplify=FALSE)) {

      # make name by concatenating the names of the elements
      # of l that we're intersecting
      name_1 &lt;- paste(names(l)[indices[-m]], collapse="_")
      name_2 &lt;- names(l)[indices[m]]
      name &lt;- paste(name_1, name_2, sep="_")

      results[[name]] &lt;- intersect(results[[name_1]], results[[name_2]])

    }
  }
  results
}


If you really want to eliminate more duplicate calculations, you can assign names(l) outside both loops and length(l) outside the outer loop.