Improve performance of concatWith.

The previous implementation of `concatWith` performs (n-1) `concat`s
of three element lists, with an overall running time that is quadratic
(in the length of the input list, assuming that elements of the input
list are of constant non-zero length).

This implementation of `concatWith` performs one `concat` of an
(2*n - 1) element list, with an overall running time that is linear.

```
[mtf@fenrir tmp]$ cat z.sml
val (n1, n2) =
   let val args = CommandLine.arguments ()
   in (valOf (Int.fromString (hd args)), valOf (Int.fromString (hd (tl args))))
   end

val l = List.tabulate (50000, fn _ => "abc")
val s = String.concatWith " " l

val _ = print (String.substring (s, n1, n2))
val _ = print "\n"
[mtf@fenrir tmp]$ /usr/bin/time ./z.20100608 99 10
 abc abc a
        9.01 real         8.98 user         0.03 sys
[mtf@fenrir tmp]$ /usr/bin/time ./z.concatWith-performance 99 10
 abc abc a
        0.02 real         0.01 user         0.00 sys
```

Thanks to David Hansel for the bug report.
Summation using `+?` cannot raise Overflow.
Improve performance of concatWith.

Commit 884a257bf1fba9e8e2281ca35a1971feb10af654 gave an indirect
implementation of `concatWith` using `concat`.  A potential
disadvantage of that implementation is that it requires the allocation
of an intermediate list.

This implementation of `concatWith` (due to Christopher Cramer) is a
direct implementation using `unfoldi`.

```
[mtf@fenrir tmp]$ cat z.sml
val (n1, n2) =
   let val args = CommandLine.arguments ()
   in (valOf (Int.fromString (hd args)), valOf (Int.fromString (hd (tl args))))
   end

val l = List.tabulate (50000, fn _ => "abc")
val s = String.concatWith " " l

val _ = print (String.substring (s, n1, n2))
val _ = print "\n"
[mtf@fenrir tmp]$ /usr/bin/time ./z.concatWith-performance.v1 @MLton gc-summary -- 99 10
 abc abc a
GC type         time ms  number           bytes       bytes/sec
-------------   ------- ------- --------------- ---------------
copying               6       3       4,178,632       696438666
mark-compact          0       0               0               -
minor                 0       0               0               -
total time: 19 ms
total GC time: 11 ms (57.9%)
max pause time: 8 ms
total bytes allocated: 10,218,648 bytes
max bytes live: 3,053,384 bytes
max heap size: 24,444,928 bytes
max stack size: 592 bytes
num cards marked: 0
bytes scanned: 0 bytes
bytes hash consed: 0 bytes
        0.02 real         0.01 user         0.00 sys
[mtf@fenrir tmp]$ /usr/bin/time ./z.concatWith-performance.v2 @MLton gc-summary -- 99 10
 abc abc a
GC type         time ms  number           bytes       bytes/sec
-------------   ------- ------- --------------- ---------------
copying               5       3       3,448,448       689689600
mark-compact          0       0               0               -
minor                 0       0               0               -
total time: 17 ms
total GC time: 9 ms (52.9%)
max pause time: 5 ms
total bytes allocated: 12,618,704 bytes
max bytes live: 2,323,200 bytes
max heap size: 18,661,376 bytes
max stack size: 592 bytes
num cards marked: 0
bytes scanned: 0 bytes
bytes hash consed: 0 bytes
        0.01 real         0.01 user         0.00 sys
```

Curiously, while this implementation is slightly faster, it has a
larger total bytes allocated, most likely due to the allocation of the
Separator/Separated variants.
Improve performance of concatWith.

Commit 681fb12c2a95f5eb7e36615ea94af39c4efd2e6c gave a direct
implementation of `concatWith` using `unfoldi` (due to Christopher
Cramer).  That implementation used an explicit data structure to
distinguish unfolding elements from a separated slice and unfolding
elements from the separator.  While faster than the implementation of
`concatWith` from commit 884a257bf1fba9e8e2281ca35a1971feb10af65, it
had a larger total bytes allocated, due to the allocation of the
explicit data structure.

This implementation uses a simple boolean to distinguish unfolding
elements from a separated slice and unfolding elements from the
separator.  While we appear to lose the known length of the separator
during the 'false' iterations of the loop, it doesn't really hurt.
The length of a slice is a field of the slice data structure, so it is
a constant time fetch and no worse than fetching it off the stack.

```
[mtf@fenrir tmp]$ /usr/bin/time ./z.concatWith-performance.v2 @MLton gc-summary -- 99 10
 abc abc a
GC type         time ms  number           bytes       bytes/sec
-------------   ------- ------- --------------- ---------------
copying               5       3       3,448,448       689689600
mark-compact          0       0               0               -
minor                 0       0               0               -
total time: 18 ms
total GC time: 9 ms (50.0%)
max pause time: 5 ms
total bytes allocated: 12,618,704 bytes
max bytes live: 2,323,200 bytes
max heap size: 18,661,376 bytes
max stack size: 592 bytes
num cards marked: 0
bytes scanned: 0 bytes
bytes hash consed: 0 bytes
        0.01 real         0.01 user         0.00 sys
[mtf@fenrir tmp]$ /usr/bin/time ./z.concatWith-performance.v3 @MLton gc-summary -- 99 10
 abc abc a
GC type         time ms  number           bytes       bytes/sec
-------------   ------- ------- --------------- ---------------
copying               1       2       1,125,256   1,125,256,000
mark-compact          0       0               0               -
minor                 0       0               0               -
total time: 8 ms
total GC time: 2 ms (25.0%)
max pause time: 2 ms
total bytes allocated: 6,618,760 bytes
max bytes live: 1,007,120 bytes
max heap size: 8,093,696 bytes
max stack size: 592 bytes
num cards marked: 0
bytes scanned: 0 bytes
bytes hash consed: 0 bytes
        0.01 real         0.00 user         0.00 sys
```
Merge pull request #23 from MatthewFluet/concatWith-performance

Improve performance of concatWith.