So here's my .02 cents coming from a software engineer perceptive...

The kernel... It's the core/kernel of an operating system. It's main functions (as stated above) are to interact with the hardware a.k.a. Device Drivers, to manage resources (things like memory management and processor time sharing a.k.a. multi-tasking), service interrupt requests, network services and the like. It also provides a System Call Interface (API) to the user space (apps running on the machine) so the apps can use system resources.

Now the why so many part... First of all in general there are MANY options available when compiling (building) the kernel. Things like CPU schedulers, file system support, system type support (in the captivates case ARM), etc. etc. etc. So there are many different ways to configure the kernel and that gives many options to "test" and see which might work better or not. Some of them are dead giveaways like compiling the kernel for MIPS and trying to run it on the captivate won't work but some are "tweaks" that may help a little or a lot, like CPU management options.

Second part of the why so many is the code. Again as mentioned above things like changing code to make the colors of the display more or less sharp (display device driver), make the file system faster (voodoo lag fix) or overclocking the processor, and different "modem" tweaks are all "enhancements" that people have made to the original Linux kernel source. So those things "creep" into existence over time, since there are many people working on them, and you see different versions of the Kernel from that as well.

Anyone that plays music can relate to the options available in that there are only 12 notes on a guitar fret board but millions (or more) ways to put them together to play music. There are certain things that have to be present in the Kernel (notes) but writing code to enhance them and/or combining options at compile time is much broader (music).

ROM. Well IMO this one has a bad nomenclature. ROM is actually Random Access Memory and we flash an image to the "ROM" (which it really isn't but I'll leave that one alone). The "ROM" in this case is the operating system (a version of embedded Linux), which is the basic software needed to run and admin the phone, things like the Kernel, bootloader, device drivers, and file system plus any user apps like the phone dialer, launcher, etc. that are included in the ROM. As you can imagine the possibilities of customization are almost endless when it comes to the ROM. Different kernels, different drivers, different apps and many combinations of those. Thus we see all the different "ROM"s for the captivate with all the different options and unfortunately problems as well.

The modem is actually part of the kernel. It's the device driver for the phone hardware of the captivate. Being that it's part of the kernel it "works with" other code that's elsewhere in the kernel and ROM that is "tweaked" for a particular phone in this case. So when you see "use an i9000 modem with an i9000 kernel" it's because the code in the modem is written to work with the other code in the kernel. It doesn't necessarily mean it will brick the phone and/or not work but it quite often means it won't work the best if it's not "matched".

An example of the why so many here might be (and I'm just using this as a random example not a real world example) in the code below (which is the Samsung modem code in the SuckerPunch source in this case) notice the comment there about "no spec" and having to confirm how much time is needed to initialize. That may be an example where someone could play with those timings and get better performance out of the modem...
static void msm_reset(struct modemctl *mc)
{
<sniped code for briefness here>

gpio_set_value(mc->gpio_cp_reset, 0);
msleep(500); /* no spec, confirm later exactly how much time
needed to initialize CP with RESET_PMU_N */

gpio_set_value(mc->gpio_cp_reset, 1);
msleep(40); /* > 37.2 + 2 msec */

gpio_set_value(mc->gpio_phone_on, 0);
gpio_set_value(mc->gpio_cp_reset, 0);
}

So that's one example of how you might get another modem version if someone played with that code and saw better performance.

I don't know if that all helps or muddies the water, but again it's just an old software engineer's .02 cents.