Как реализовать вариадическую чистую функцию без классов типов?
Пока описал задачу, сам понял, как её нужно решать. ))function add(x) {
	return function(y) {
		return x + y;
	};
}

function sum(a) {
	return function(b) {
		if (b) {
			return sum(add(a)(b));
		} else {
			return a;
		}
	};
}

sum(1)(2)(3)(4)(5)() === 15function cons(x) {
	return function(y) {
		return [x, y];
	};
}

function list(a) {
	return function(b) {
		if (b) {
			return list(cons(a)(b));
		} else {
			return a;
		}
	};
}

list(1)(2)(3)(4)(5)() === [[[[1, 2], 3], 4], 5]Update
Скорректированный код для второго случая, возвращающий более каноничный вид списка:function cons(x) {
  return function(y) {
    return [x, y];
  };
}

function list(a) {
  return function(b) {
    if (typeof b !== 'undefined') {
      if (a instanceof Array) {
          return list(cons(b)(a));
      } else {
          return list(cons(b)(cons(a)('NIL')));
      }
    } else {
      return a;
    }
  };
}

list(1)(2)(0)(4)(5)() === [5,[4,[0,[2,[1,"NIL"]]]]]
Хотя список всё равно создаётся в обратном порядке.
Вы уверены что хотели получить именно такой массив?
По поводу той же суммы дам вам интересную идею на поиграться:function sum(a) {
  var sum = a;
  
  function _sum(b) {
    if (b === undefined) return sum;
    
    sum += b;
    return _sum;
  }
  
  _sum.toString = function() {
    return sum;
  };
  
  return _sum;
}

sum(1)(2)(3) + sum(2)(2) + sum(sum(1)(2)(3))(4)(5); // 25
Некоторые отличия в этой реализации:
1. Чуть реже создаются новые функции (у вас новая функция появляется при каждом вызове).
2. Не обязателен последний вызов, чтобы получить значение. Т.е. так же есть возможность получить промежуточное значение и продолжить вычисления. Вообще если вы уверены что в операциях будут участвовать только числа, было бы правильнее определить valueOf, но toString универсальнее.
3. Ваша реализация не учитывает sum(1)(2)(0)(3)()