Search refactor predecessors: ImmutableStack, Option, More Extensions

@ikeough @lukechurch As discussed in https://github.com/DynamoDS/Dynamo/pull/3463
I did not get around to writing tests, but it should be fairly straightforward as it's an immutable API.

```csharp
var leaves = new[] { "mercury", "venus", "moon", "mars", "jupiter", "tuxedo mask" };
var grouped = leaves.GroupByRecursive(leaf => new[] { leaf.Where(IsVowel).Count(), leaf.Where(IsConsonant).Count() });

var rootCategories = grouped.Select(group => group.Key.LeftValue).OrderByAscending();
Assert.AreEqual(new[] { 1, 2, 3, 4 }, rootCategories); // Different vowel counts

var sub1keys = grouped.First().Select(group => group.Key.LeftValue).OrderByAscending();
Assert.AreEqual(new[] { 2, 3, 5 }, sub1keys); // For vowel count of 2, different consonant counts

Assert.IsTrue(grouped.First().All(group => group.All(leaf => !leaf.IsLeft))); // At three layers, no more sub categories
var sub1 = grouped.First().SelectMany(group => group.Select(leaf => leaf.RightValue));
Assert.AreEqual(new[] { "mercury", "venus", "moon" }, sub1); // All 3 vowel words

//...etc...
```