File: notes.txt

package info (click to toggle)
mlton 20210117%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 58,464 kB
  • sloc: ansic: 27,682; sh: 4,455; asm: 3,569; lisp: 2,879; makefile: 2,347; perl: 1,169; python: 191; pascal: 68; javascript: 7
file content (1360 lines) | stat: -rw-r--r-- 52,674 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360

Date: Tue, 23 Jul 2002 11:49:57 -0400 (EDT)
From: Matthew Fluet <fluet@CS.Cornell.EDU>


John and SML implementers,

Here are a loose collection of notes I've taken while starting to
update the MLton implementation of the SML Basis Library to the latest
version.  They span quite a range: errata and typos, signature
constraint concerns, and some design questions.  Thus far, I've looked
at the structures that had been grouped under the headings General,
Text, Integer, Reals, Lists, and Arrays and Vectors (i.e., excluding
IO, System, and Posix) in the "old" web specification.

A few high level comments:

* As an organizational principal, I liked the grouping of modules into
  larger collections used in the "old" web specification better than
  the long alphabetical list.
* I'm quite happy to see opaque signature matches for most structures.
  In particular, I think it will help avoid porting problems between
  implementations that provide different INTEGER structures, especially
  when LargeInt = Int in one implementation and LargeInt = IntInf in 
  another.

Required and optional components, Top-level:

* A number of structures have an opaque signature match in
  overview.html, but not in the corresponding structure specific page:
  General, Bool, Option, List, ListPair, IntInf, 
  Array, ArraySlice, Vector, VectorSlice.
* Word8Array2 is listed as required in overview.html,
  but its signature, MONO_ARRAY2, is not required.
  Furthermore, Word8Array2 is marked optional in mono-array2.html.
  I don't quite see a rationale for Word8Array2 being required.
* With the addition of  val ~ : word -> word  to the WORD signature,
  presumably ~ should be overloaded at num, rather than at intreal.

Reals:

* In pack-float.html, the where type clauses are incorrect:
  structure PackRealBig :> PACK_REAL  
    where type PackRealBig.real = Real.real
  should be
  structure PackRealBig :> PACK_REAL  
    where type real = Real.real
* Likewise, in most places, references to basic types are unqualifed,
  so perhaps the where clause should read
  where type real = real
  for the PackRealBig and PackRealLittle structures.

Arrays and Vectors:

* In vector-slice.html, the description of subslice references |arr|
  when it should reference |sl|.
* In {[mono-]array[-slice],[mono-]vector[-slice]}.html, the
  description of findi references appi when it should reference findi.
* In mono-array-slice.html, structure CharArraySlice has the clause
  where type array = CharVector.vector
  which should be
  where type array = CharArray.array.
* In mono-{vector[-slice],array[-slice],array2}.html, there are
  Word<N> structures but no (default word) Word structures.
* In mono-vector.html, structure CharVector has the clause
  where type elem = Char.char
  while the other monomorphic vectors of basic types reference
  the unqualified type; i.e. structure BoolVector has the clause
  where type elem = bool.
* There are no "See also"'s into MONO_VECTOR_SLICE or MONO_ARRAY_SLICE
  from MONO_VECTOR or MONO_ARRAY.
* A long discussion about types defined in
  [MONO_]{ARRAY,VECTOR}[_SLICE] signatures; deferred to a separate
  email. 

Really nit-picky:

* Ordering of comparison functions (>, >=, etc.) and unary negation
  are different within INTEGER and WORD.
* Ordering of functions in CHAR seems awkward.
* Ordering of full, slice, subslice different in ARRAY_SLICE and
  VECTOR_SLICE. 
* Ordering of foldi/fold and modifi/modify different in ARRAY2 and
  MONO_ARRAY2. 

Top-level and opaque signatures:
* I think it would be useful to see the entire top-level of required
  structures written out with their respective signature constraints.
  For example, in the description of the Math structure, the spec
  reads: "The top-level structure Math provides these functions for
  the default real type Real.real."  Because the top-level Math
  structure has an opaque signature match (in overview.html), then the
  sentence above implies that there ought to be the constraint 
  where type real = real (or Real.real).  
  Granted, none of the other structures in overview.html have where
  clauses, and most type constraints are documented in the structure
  specific pages, but the constraint on the top-level Math.real
  slipped my mind when I first looked at it.

-Matthew

******************************************************************************
******************************************************************************

Date: Tue, 23 Jul 2002 11:54:09 -0400 (EDT)
From: Matthew Fluet <fluet@CS.Cornell.EDU>


As promised, here is a longish look at the types used in Arrays and
Vectors.

Array and Vector design:

* The ARRAY signature includes type 'a vector.
  Presumably, type 'a Array.vector = type 'a Vector.vector, but no
  constraint makes this explicit.
* MONO_ARRAY_SLICE includes type vector and type vector_slice, 
  while the ARRAY_SLICE signature explicitly references 
  'a VectorSlice.slice and 'a Vector.vector.
* VECTOR_SLICE doesn't include 'a vector, but has
  val mapi : (int * 'a -> 'b) -> 'a slice -> 'b vector
  val map  : ('a -> 'b) -> 'a slice -> 'b vector;
  On the other hand, full, slice, base, vector, and concat
  reference 'a Vector.vector.

For consistency, I'd prefer to see
signature VECTOR = 
  sig  type 'a vector  ... end
signature VECTOR_SLICE = 
  sig  type 'a vector  type 'a slice  ... end 
signature ARRAY = 
  sig  type 'a vector  type 'a array  ... end
signature ARRAY_SLICE = 
  sig  type 'a vector  type 'a vector_slice
       tyep 'a array  type 'a slice  ... end
signature MONO_VECTOR = 
  sig  type elem  type vector  ... end
signature MONO_VECTOR_SLICE = 
  sig  type elem  type vector  type slice ... end
signature MONO_ARRAY =
  sig  type elem  type vector  type array  ... end
signature MONO_ARRAY_SLICE =
  sig  type elem  type vector  type vector_slice
       type array  type slice  ... end

structure Vector :> VECTOR
structure VectorSlice :> VECTOR_SLICE 
                         where type 'a vector = 'a Vector.vector
structure Array :> ARRAY 
                   where type 'a vector = 'a Vector.vector
structure ArraySlice :> ARRAY_SLICE 
                        where type 'a vector = 'a Vector
                        where type 'a vector_slice = 'a VectorSlice.slice
                        where type 'a array = 'a Array.array
structure BoolVector :> MONO_VECTOR 
                        where type elem = bool
structure BoolVectorSlice :> MONO_VECTOR_SLICE 
                             where type elem = bool
                             where type vector = BoolVector.vector
structure BoolArray :> MONO_ARRAY 
                       where type elem = bool
                       where type vector = BoolVector.vector
structure BoolArraySlice :> MONO_ARRAY_SLICE 
                            where type elem = bool
                            where type vector = BoolVector.vector
                            where type vector_slice = BoolVectorSlice.slice
                            where type array = BoolArray.array

While semantically, this shouldn't be any different than the
specification, it could effect type-error messages.  For example, if I
have the structure Foo:

structure Foo = struct
   open BoolArraySlice

   val copyVec0 {src: vector_slice, 
                 dst: array} = copyVec {src = src, dst = dst, di = 0}   
end

which I decide to generalize to polymorphic array slices, then just
changing BoolArraySlice to ArraySlice will lead to different
type-error messages: either "ubound type constructor: vector_slice"
(under the specification) or "type constructor vector_slice given 0
arguments, wants 1" (under the signatures given above); and an arity
error for array in either case.  It's not much of an argument, but I
need to replace vector_slice with 'a VectorSlice.slice under the
specification, while I only need to add 'a under the sigs above.


Array2:
* Why not have an ARRAY2_REGION analagous to ARRAY_SLICE?
  Likewise, how about VECTOR2 and VECTOR2_REGION?
  I think the decision to separate Arrays and Vectors from
  their corresponding slices is a nice design choice, and I'd be in
  favor of extending it to multi-dimentional ones.
* Should ARRAY2 have findi/find, exists, all?  collate?

******************************************************************************
******************************************************************************

Date: Thu, 25 Jul 2002 15:20:01 +0200
From: Andreas Rossberg <rossberg@ps.uni-sb.de>


Like Matthew I started implementing the latest version of the Basis spec
for Alice and Hamlet. I'm quite happy with most of the changes. It was a
surprise to discover the presence of a Windows structure, though :-)

Here is my list of comments, some of which may duplicate observations
already made by Matthew. They primarily cover global issues and the
required part of the library, though I haven't looked deeper into the IO
and Posix parts yet. I also included some proposals for modest additions
to the library, which I believe are useful and fit its spirit.


Trivial bugs, typos, cosmetics
------------------------------

* Overview:
  - INT_INF appears in the list of required signatures.
  - WordArray2 appears under the list of required structures,
    instead of optional ones.

* LIST_PAIR:
  - Typo in description of allEq: double "the".

* SUBSTRING:
  - The scan example uses the deprecated "all" function.

* VECTOR_SLICE:
  - Typo in synopsis of subslice: s/opt/sz/.
  - Typo in description of subslice: s/|arr|/|sl|/.
  - Typo in description of findi: s/appi/findi/.
  - Signature sometimes uses Vector.vector instead of plain vector.
  - The equation for mapi can be simplified to:
        Vector.fromList (foldri (fn (i,a,l) => f(i,a)::l) [] slice)

* MONO_VECTOR_SLICE and ARRAY_SLICE and MONO_ARRAY_SLICE:
  - Typo in synopsis of subslice: s/opt/sz/.
  - Typo in description of findi: s/appi/findi/.

* BYTE:
  - Accidental "val" keyword in synopsis of some functions.

* TEXT_IO:
  - The "where" constraints contain erroneously qualified ids.
  - The specification of the TEXT_IO signature is not valid SML'97,
    since StreamIO is specified twice. You might want to add a
    comment regarding that.
  - The constraints for types vector and elem are redundant
    (in fact, invalid), because the signature TEXT_STREAM_IO
    already specifies the necessary equations.

* The use of variable names is sometimes inconsistent:
  - Predicate arguments to higher-order functions are usually
    named "f" (eg. List.all), sometimes "p" (eg. String.tokens,
    StringCvt.splitl), and sometimes even "pred" (eg. ListPair.all).
  - Similarly, fold functions mostly use "init" to name initial
    accumulators, except in the List and ListPair modules.



Ambiguities / Unclear Details
-----------------------------

* Overview:
  - The subsection about dependencies among optional modules has
    disappeared. Does that mean that there aren't any anymore?
    (The nice subsection about design rules and conventions also
    has gone.)

* The intended meaning of opaque signature constraints is not always
  clear to me. Sometimes the prose contains remarks about additional
  equalities that are not appearent from the signature constraints.
  For example, is or isn't
  - Text.Char.char = Char.char ? (and so on for the rest of Text)
  - LargeInt.int = IntN.int (for some structure IntN) ?
    (likewise LargeWord.word, LargeReal.real)
  - Char.string = String.string ?
  - Math.real = Real.real ?
  In particular, the spec sometimes speaks of "equal structures",
  which has no real technical meaning in SML'97.
  Note that from the opaque matching on the overview page one might
  even conclude that General.unit <> {} !

* The type specification of String.string and CharVector.vector
  is circular:
        structure String :> STRING
               where type string = CharVector.vector
        structure CharVector :> MONO_VECTOR
               where type vector = String.string
  Likewise for Substring.substring and CharVectorSlice.slice.
  A respective defining structure should be chosen.

* STRING:
  - Function fromString has a special case that is not covered by
    implementing the function through straight-forward iterative
    application of the Char.scan function, namely a trailing gap
    escape (\f...f\) as in "foo\\ \\" or "foo\\ \\\000" (where \000
    is an non-convertible character). Several implementations I
    tried get that detail wrong, so a corresponding note might be
    in order. Moreover, it is not completely obvious from the
    description what the result should be for strings that contain
    a gap escape as the only convertible sequence, e.g. "\\ \\" or
    "\\ \\\000" - it is supposed to be SOME "", I guess.

* SUBSTRING:
  - Shouldn't span raise Span if i' < i? Otherwise, contrary
    to the prose, it in fact accepts arguments where ss' is
    left to ss, as long as they overlap (which is rather odd).
  - For the curried triml/trimr it is not clear whether an
    Subscript exception has to be raised already if k < 0 but no
    second argument is applied.



Naming and structuring
----------------------

Its nicely chosen regular naming conventions and structure are two of
the aspects I like most about the Standard Basis. The following list
enumerates the few cases where I feel that the spec violates its own
conventions.

* WORD:
  - The fromLargeWord and toLargeWord functions should drop
    the "Word" suffix to be consistent with the corresponding
    functions in the REAL and INTEGER signatures.

* CHAR:
  - The functions contains/notContains should be moved to the
    STRING signature, as they are similar to find/exist
    operations and thus functionality of the aggregate. The
    type string could then be removed from the signature.

* ARRAY_SLICE and MONO_ARRAY_SLICE:
  - The function copyVec seems completely out of place: it does
    neither operate on array slices, nor on vectors. But honestly
    I have got no idea where else to put it :-(

* STRING and SUBSTRING:
  - There is a certain asymmetry between slices and substrings
    which tends to confuse at least myself when hacking. For more
    consistency I propose:
    (1) changing the type of Substring.substring to
        string * int * int option -> substring
        (for consistency with VectorSlice.slice),
    (2) renaming Substring.slice to Substring.subsubstring,
        (for consistency with VectorSlice.subslice),
    (3) removing Substring.{app,foldl,foldr} (there are no similar
        functions in the STRING signature, and in both cases they
        are available through CharVector/CharVectorSlice),
    (4) removing String.extract and Substring.extract (the same
        functionality is available through CharVector[Slice]).
  - I believe the deprecated Substring.all can be removed for good.
    After all, there are more serious incompatible changes being
    made (e.g. array copying functions).

* Vectors and arrays:
  - While the lib consistently uses the to/from convention for
    conversions on basic types, it sometimes uses adhoc conventions
    for aggregates. I propose renaming:
    (1) Array.vector to Array.toVector
    (2) VectorSlice.vector to VectorSlice.toVector,
    (3) ArraySlice.vector to ArraySlice.toVector,
    (4) Substring.string to Substring.toString,
  - Since the copy functions have only 3, mostly distinctly typed
    arguments now, there no longer seems to be a strong reason to
    require passing those by notationally heavy records.

* INT_INF:
  - The presence of bit fiddling operators in that signature is
    something that feels exceptionally ad-hoc. Either they should
    be available for all integer types, or there should be a
    separate WORD_INF, with appropriate conversions, that makes
    these available.

* Toplevel:
  - Now that there is Word.~ (which is good) it seems rather odd
    that the toplevel ~ is not overloaded for words, i.e. does not
    have type num-> num.

* Net functionality:
  - I really like the idea of structuring the library namespace as
    it has been done with the OS and Posix structures. I would
    prefer to see something similar being done for the added
    network functionality. More precisely, I propose
    (1) moving the structures Socket, INetSock, GenericSock, and
        the three Net*DB structures into a new wrapper structure
        Net (renaming Net*DB to *DB),
    (2) defining a corresponding signature NET,
    (3) renaming the signatures SOCKET, GENERIC_SOCK and INET_SOCK
        to NET_SOCKET, NET_GENERIC_SOCK and NET_INET_SOCK, resp.,
    (4) moving UnixSock to the Unix structure (renamed as Socket).



Misc. proposals for additional functionality
--------------------------------------------

Here is a small collection of miscellaneous simple functions which I
believe the library is still lacking, either because they are commonly
useful or because they would make the library more regular.

* LIST and LIST_PAIR:
  - The IMHO single most convenient extension to the library would
    be indexed morphisms on lists, i.e. adding
        val appi : (int * 'a -> unit) -> 'a list -> unit
        val mapi : (int * 'a -> 'b) -> 'a list -> 'b list
        val foldli : (int * 'a * 'b -> 'b) -> 'b -> 'a list -> 'b
        val foldri : (int * 'a * 'b -> 'b) -> 'b -> 'a list -> 'b
        val findi : (int * 'a -> bool) -> 'a list -> (int * 'a) option
  - Likewise for LIST_PAIR.
  - LIST_PAIR does not support partial mapping:
        val mapPartial : ('a * 'b -> 'c option) ->
                                'a list * 'b list -> 'c list

* LIST, VECTOR, ARRAY, etc.:
  - Another function on lists that would be very useful from my
    perspective is
        val appr : ('a -> unit) -> 'a list -> unit
    and its indexed sibling
        val appri : (int * 'a -> unit) -> 'a list -> unit
    which traverse the list from right to left.
  - Likewise for all aggregate types.
  - All aggregates come with a fromList function. I often feel the
    need to have inverse toList functions. Use of foldr is obfuscating.

* OPTION:
  - Often using isSome is a bit clumsy. I thus propose adding the dual
        val isNone : 'a option -> bool

* STRING and SUBSTRING:
  - For historical reasons we have {String,Substring}.size instead
    of *.length, which is inconsistent with all other aggregates and
    frequently lets me mix them up when I use them side by side.
    I propose adding aliases
        String.maxLen
        String.length
        Substring.length

* WideChar and WideString:
  - There is no convenient way to convert between the standard and
    wide character set. Would it be reasonable to introduce LargeChar
    and LargeString structures (and so on) and have the CHAR and
    STRING signatures enriched by fromLarge/toLarge functions, as for
    numbers? That would also allow a program to select the widest
    character set available (which is currently impossible within the
    language).

* String conversion:
  - I don't quite see the rationale for which signatures contain a
    scan function and which don't. I believe it makes sense to have
    scan in every signature that has fromString.
  - There should be a function
        val scanC : (Char.char, 'a) StringCvt.reader
                        -> (char, 'a) StringCvt.reader
    to scan strings as C characters. This would make Char.fromCString
    and particularly String.fromCString more modular.
  - How about a dual writer abstraction as with
        type ('a,'b) writer = 'a * 'b -> 'b option
    and supporting fmt functions for basic types? Such a thing might
    be useful for writing to streams or buffers.

* Vectors:
  For some time now I have been trying to use vectors more often
  instead of an often inappropriate list representation. This is
  sometimes made more difficult simply because the library support
  isn't as good as for lists. It improved in the updated version
  but still I miss:
  - Array.fromVector,
  - Vector.mapPartial,
  - Vector.rev,
  - Vector.append (though I guess concat is good enough),
  - most of all: a VectorPair structure.

* Hash functions:
  - Giving every basic type a (default) hash function in addition to
    comparison would be quite useful in conjunction with container
    libraries.

* There is no defining structure for references. I would like to see
        signature REF
        structure Ref : REF
  where REF contains:
        datatype ref = datatype ref
        val ! : 'a ref -> 'a
        val := : 'a ref * 'a -> unit
        val swap : 'a ref * 'a ref -> unit      (* or :=: ? *)
        val map : ('a -> 'a) -> 'a ref -> 'a ref
  You might then consider removing ! and := from GENERAL.

* Signature conventions:
  Some additional conventions would make use of Basis types as
  functor arguments more convenient:
  - Each signature defining an abstract type should make that
    type available under the alias "t" as well (this includes
    monomorphic types as well as polymorphic ones).
  - Every equality type should come with an explicit equality
    function
        val eq : t * t -> bool
    to move away from the reliance on eqtypes.
  - There should be a uniform name for canonical constructor
    functions, e.g. "new" (or at least an alias).

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

******************************************************************************
******************************************************************************

Date: Fri, 2 Aug 2002 14:04:16 +0100
From: David Matthews <David.Matthews@deanvillage.com>


I've been having another look at the Basis library implementation in 
Poly/ML and in particular the I/O library.  I'm still not sure I fully 
understand the implications of the Stream IO (functional IO) layer and 
in particular the way "canInput" works and interacts with "input".

The definition says that canInput(f, n) returns SOME k "if a call to 
input would return immediately with at least k characters".  
Specifically it does not say "if a call to inputN(f, k) would return 
immediately".   Secondly it says that it "should attempt to return as 
large a k as possible" and gives the example of a buffer containing 10 
characters with the user calling canInput(f, 15).  This suggests that a 
call to canInput could have the effect of committing the stream since a 
perfectly good implementation of "input" would be to return what was 
left of the buffer, i.e. 10 characters, and only read  from the 
underlying stream on a subsequent call to "input".  Yet after a call to 
canInput(f, 15) which returns SOME 15 the call to "input" is forced to 
return at least 15.  In other words a call to canInput changes the 
behaviour of a subsequent call to "input".  Generally, what is the 
behaviour of canInput with an argument larger than the buffer size?  How 
far ahead is canInput expected to read?

A few other notes of things I've discovered, some of which are trivial:

The signature for TextIO.StreamIO contains duplicates of
  where type StreamIO.reader = TextPrimIO.reader
  where type StreamIO.writer = TextPrimIO.writer

There are declared constants for platformWin32Windows2000 and 
platformWin32WindowsXP in the Windows structure.  When I proposed the 
Windows.Config structure I didn't include constants for these versions 
of the OS because the underlying GetVersionEx function returns the same 
value, VER_PLATFORM_WIN32_NT in the dwPlatformId field for NT, Windows 
2000 and XP   It is possible to distinguish these but only using the 
major and minor version fields.  Windows CE does give a different value 
for the platformID.  I would say it is confusing to have these here 
because it implies that it's possible to discriminate on the basis of 
the platformID field.

The example definition of input1 at the bottom of STREAM_IO returns a 
value of type elem option * instream when the signature says it should 
be (elem * instream) option.

Description of "input" function in STREAM_IO signature.  The word "ay" 
should be "may".

--
David.

******************************************************************************
******************************************************************************

Date: Fri, 11 Oct 2002 17:46:59 -0400 (EDT)
From: Matthew Fluet <fluet@CS.Cornell.EDU>


Following up my previous post, here is another loose collection of
notes I've taken while updating the MLton implementation of the SML
Basis Library.  This includes the structures that had been grouped
under the headings System, Posix, and IO in the "old" web
specification.

Required and optional components:
* The optional functors PrimIO, StreamIO, and ImperativeIO are not
  listed among the optional components in overview.html.

Lists:
* The discussion for the ListPair structure says:
  "Note that a function requiring equal length arguments may determine
  this lazily, i.e. , it may act as though the lists have equal length
  and invoke the user-supplied function argument, but raise the
  exception when it arrives at the end of one list before the end of the
  other."
  Such an implementation choice seems to go against the spirit that
  programs run under conforming implementations of the Basis Library
  should behave the same.

Posix:
* In posix.html, last sentence in Discussion: "onsult" instead of
  "consult"
PosixSignal:
* In posix-signal.html, in Discussion: "The name of the coressponding
  ..." sentence is repeated.
PosixError:
* In the discussion of POSIX_ERROR:
  "The name of a corresponding POSIX error can be derived by
  capitalizing all letters and adding the character ``E'' as a
  prefix. For example, the POSIX error associated with nodev is
  ENODEV. The only exception to this rule is the error toobig, whose
  associated POSIX error is E2BIG."
  It isn't clear if this is the intended semantics for errorName and
  syserror.

Time:
* The type time now includes "negative values moving to the past."
  In the absence of negative values, the text for the the
  to{Seconds,Milliseconds,Microseconds} functions to drop fractions of
  the time unit was unambigous.  With negative values, I would
  interpret this as rounding towards zero.  Is this correct?  Would it
  be clearer to describe the rounding as such?
* The + and - functions are required to raise Overflow, although most
  other "result not representable as a time value" error raises Time.
* The - function is written prefix instead of infix in the
  description.
* The scan and fromString functions do not specify how to treat a
  value with greater precision than the internal representation;
  should it have rounding or truncation semantics?  Also, the
  functions are required to raise Overflow for an unrepresentable
  time value.

IO:
* The nice introduction to IO that appears at
  http://cm.bell-labs.com/cm/cs/what/smlnj/doc/basis/pages/io-explain.html
  doesn't seem to be included with the new pages.
* The functor arguments in PrimIO, StreamIO, and ImperativIO functors
  don't match; some use structure A: MONO_ARRAY and others use
  structure Array: MONO_ARRAY.

PrimIO() and PRIM_IO
* The PRIM_IO signature requires pos to be an eqtype, but the PrimIO
  functor argument only requires pos to be a type.
* readArr[NB], write{Vec,Arr}[NB] take "slices" (records of type {buf:
  {vector,array}, i: int, sz: int option}) but no description of the
  appropriate action to take when the slices are invalid.  Presumably,
  they should raise Subscript.
* There are a number of "contradictory" statments:
  "Readers and writers should not, in general, raise the IO.Io
  exception. It is assumed that the higher levels will appropriately
  handle these exceptions."
  "A reader is required to raise IO.Io if any of its functions, except
  close or getPos, is invoked after a call to close. A writer is
  required to raise IO.Io if any of its functions, except close, is
  invoked after a call to close."
  "closes the reader and frees operating system resources. Further
  operations on the reader (besides close and getPos) raise
  IO.ClosedStream."
  "closes the writer and frees operating system resources. Further
  operations (other than close) raise IO.ClosedStream."
* The augment_reader and augment_writer functions may introduce new
  functions.  Should the synthesized operations handle IO.Io
  exceptions and change the function field?  Maybe this falls under
  the "intentionally unspecified" clause.

StreamIO() and STREAM_IO:
* What is the difference between a terminated output stream and a
  closed output stream?  Some operations say what to do when the
  stream is terminated or closed, but many are unspecified when the
  other condition holds.  I resolved this by looking at the IO
  introduction mentioned above, where it discusses stream states.
  But, closeOut is still confusing: "flushes f's buffers, marks the
  stream closed, and closes the underlying writer. This operation has
  no effect if f is already closed. If f is terminated, it should
  close the underlying writer."  Shouldn't closeOut always execute the
  underlying writer's close function?  The only way to terminate an
  outstream is to getOutstream, but I would really expect
  TextIO.closeOut to "really" close the underlying
  file/outstream/writer.
* The IO structure has dropped the TerminatedStream exception, but
  there seem to be sufficient cases when a stream should raise an
  exception when it is terminated.
* The semantics of the vector returned by getReader are unclear.  At
  the very least, the source code for SML/NJ and PolyML have very
  different interpretations, and I've chosen yet another.  I think
  part of the problem is that the word "[un]consumed" only appears in
  the description of this function, so it's unclear what corresponds
  to consumed input.
* I suspect the example under endOfStream is wrong:

  In these cases the StreamIO.instream will also have multiple EOF's;
  that is, it can be that

  val true = endOfStream(f)
  val ("",f') = input f
  val true = endOfStream(f')
  val ("xyz",f'') = input f

  The fact that input f can return two different values would seem to
  violate the principal argument for functional streams!  Looking at
  the aforementioned IO introduction in the "old" pages, I see the
  more reasonable example:

  Consequently, the following is not guaranteed to be true:

  let val z = TextIO.StreamIO.endOfStream f
      val (a,f') = TextIO.StreamIO.input f
      val x = TextIO.StreamIO.endOfStream f'
  in x=z   (* not necessarily true! *)
  end

  whereas the following is guaranteed to be true:

  let val z = TextIO.StreamIO.endOfStream f
      val (a,f') = TextIO.StreamIO.input f
      val x = TextIO.StreamIO.endOfStream f (* note, no prime! *)
  in x=z   (* guaranteed true! *)
  end
* David Matthews's post on Aug. 2 raised questions about canInput
  which are unresolved.

General comments:
* Various operations in IO take "slices", but aren't expressed in
  terms of {Vector,Array}Slice structures.  One difficulty with this
  is that the slice types are not in scope within the IO signatures.  

  I would really advocate making the VectorSlice structure a
  substructure of the Vector structure (and likewise for arrays).
  Even if this isn't done for the polymorphic vector/array structures,
  it would be extremely beneficial for the monomorphic structures,
  where in the {Prim,Stream,Imperative}IO functors, it is impossible
  to access the corresponding monomorphic vector/array slice
  structures.  I found myself using Vector.tabulate when I really
  wanted ArraySlice.vector.

  The "old" MONO_ARRAY signature included structure Vector:
  MONO_VECTOR which gave access to the corresponding monomorphic
  vectors.

-Matthew

******************************************************************************
******************************************************************************

Date: Fri, 13 Dec 2002 15:57:55 +0100
From: Andreas Rossberg <rossberg@ps.uni-sb.de>


Here is a collection of issues and comments we gathered when
implementing the I/O stack from the Standard Basis (primitive, stream,
imperative I/O) for Alice. While in general the specification seems to
be pretty precise and complete, we sometimes found it hard to understand
the semantic details of stream I/O, especially since many of them can
only be derived indirectly from the examples in the discussion section
and there appear to be some minor ambiguities and inconsistencies. Also,
the PrimIO and StreamIO functors cannot always be implemented as
suggested, because of their parametricity in types such as position and
element.

As a general note, the I/O interface does not seem to have been designed
with concurrency in mind. In particular, augmenting readers and writers
cannot be made thread-safe, AFAWCS. This is a bit of a problem for us,
since Alice is relying on concurrency. However, that does not seem to be
an issue easily solved.

        - Leif Kornstaedt, Andreas Rossberg


The IO structure
----------------

* exception Io:

  - function field: (pedantic) The wording seems to imply that only
    functions from STREAM_IO raise the Io exception, but this is
    clearly not the case (consider TextIO.openIn to name just one).

* datatype buffer_mode:

  - There is no specification of what precisely line buffering is
    supposed to mean, in particular for non-text streams.



The PRIM_IO signature
---------------------

* Synopsis:

  - (pedantic) It says that "higher level I/O facilities do not
    access the OS structure directly...". That's somewhat misleading
    since OS does not provide the same functionality anyway (if any,
    it was the Posix structure).

* type reader:

  - Unlike for writers, it is not specified what the minimal set of
    operations is that a reader must support.

  - It is not specified whether multiple end-of-streams may occur.
    Since they are anticipated for StreamIO, one should expect them
    to be possible for underlying readers as well. However, this
    requires clarification of the semantics of several operations.

  - readArr, readArrNB: It is specified nowhere what the option for
    sz is supposed to mean, i.e. what the semantics of NONE is
    (presumably as for slices).

  - readVec, readVecNB: Unlike all other similar read and write
    functions, these two do not accept an option for the size
    argument.

  - avail: The description suggests that the function can be used as
    a hint by inputAll. However, this information is too inaccurate
    to be useful, since (apart from translation issues) the physical
    size of elements cannot be obtained (in particular in the
    StreamIO functor, which is parametric in the element type). In
    practice, endPos seems to be more useful for this purpose. So it
    is not clear what purpose avail could actually serve at all at
    the abstraction level provided by readers.

  - endPos:
    (1) May it block? For example, when reading from terminal or
    from another kind of stream, this can be naturally expected.

    (2) Which position is returned if there are multiple
    end-of-streams?

  - getPos, setPos, endPos, verifyPos: Description should start with
    "when present".

  - setPos, endPos: Should not raise an exception if unimplemented,
    but rather be NONE. Actually, the implementation notes on writers
    state that endPos *must* be implemented for readers.

  - Implementation note, item 6: Why is it likely that the client
    uses getPos frequently? And why should the reader count
    *untranslated* elements (and how would there be actual elements
    before translation)?
    (See also comments on STREAM_IO.filePosIn)

* type writer:

  - writeVec, writeArr, writeVecNB, writeArrNB:
    (1) Again, it is not specified what the optional size means.

    (2) When may k < sz occur without having IO failure? If it is
    arbitrary, then there appears to be no correct way to write a
    sequence of elements, because it is neither possible to detect
    partial element writes (which are explained in the paragraph
    before the Implementation Notes), nor to complete such writes.
    This particularly implies that the StreamIO functor cannot
    implement flushing correctly (see below).

  - getPos, setPos, endPos, verifyPos: Description should start with
    "when present".

  - getPos, setPos: Should not raise an exception if unimplemented,
    but rather be NONE.

  - last paragraph before Implementation Note: Typo, double "plus".

  - first sentence in Implementation Note: (pedantic) Why is this
    put into the implementation notes when it actually seems to be a
    requirement of the specification?

  - last paragraph of Implementation Note:
    (1) States that readers must implement getPos, which seems to be
    contradicted by its optional type.

    (2) Typo, double "need".

* openVector:

  - Is this supposed to support random access? Note that for types
    generated with the PrimIO functor it cannot (see below)! That
    seems to make this function rather useless.

* augmentReader, augmentWriter:

  - It is not possible to synthesize operations in a way that is
    thread-safe in concurrent systems, hence it should be noted that
    augmenting is potentially dangerous.

* There is no reference to the PrimIO functor.



The PrimIO functor
------------------

* General problems:

  - Since the implementation is necessarily parametric in the pos
    type, openVector, nullRd, nullWr cannot create readers that
    allow random access, although one would expect that at least for
    openVector.

* Functor argument:

  - Structure names A and V are inconsistent with the StreamIO and
    ImperativeIO functors.

  - Type pos has to be an eqtype to match the result signature.

  - Since the extract and copy functions have been removed/changed
    from ARRAY and VECTOR signatures, the PrimIO functor now
    naturally requires slice structures for efficient
    implementation. (Likewise the StreamIO functor)

* Functor result:

  - Type sharing of the pos type is not specified, though essential
    for this functor being useful at all.




The STREAM_IO signature
-----------------------

* Synopsis:

  - An exception likely to be raised in by the underlying
    reader/writer is Size, which is not mentioned. OTOH, Fail can
    only occur in the rare case of user-supplied readers/writers, as
    the Basis itself is supposed to never raise it.

* type out_pos:

  - A note on the meaning of this type would be desirable, since its
    canonical representation is (outstream * pos) rather than pos.
    (That also may have caused confusion in the discussion of
    imperative I/O, see below.)

* input1:

  - The signature of this function is inconsistent with all other
    input functions. It should rather have type

        instream -> elem option * instream

    which in fact appears to be the type assumed in the discussion
    example relating input1 to inputN.

* input:

  - Typo, s/ay/may/

* inputN:

  - This function is somewhat underspecified for n=0. In particular,
    may it block? Is it required to raise Io if the underlying
    reader is closed?

* input, input1, inputN, inputAll:

  - (pedantic) Descriptions speak of "underlying system calls",
    although the reader may not actually depend on system calls.
    Preferably speak of "underlying reader" only.

* closeIn:

  - Likewise, description speaks of "releasing system resources".
    This should be replaced by saying that it closes the underlying
    reader (which is not even specified as is).

* closeOut:

  - Does the function attempt to close the stream even if flushing
    fails?

  - Why is it possible to close terminated streams? That seems to
    allow unfortunate interference with another stream that has been
    created from the extracted writer.

* mkInstream, getReader:

  - The table seems to imply that mkInstream always augments its
    reader. This is inappropriate for concurrent environments (see
    above).

  - Should getReader return the original or the augmented reader?

  - The table still includes the removed getPosIn and setPosIn
    functions.

* mkOutstream, getWriter:

  - Likewise.

* filePosIn:

  - There seems to be no way to implement this function for buffered
    I/O, because the reader position that corresponds to a
    mid-block-element is not available and cannot be calculated in
    general. So how is this meant?

  - Typo, s/character/element/

* filePosOut:

  - Likewise.

* getWriter:

  - It is non-obvious what the precise meaning of "terminating" a
    stream is. If this is merely setting a status flag then a
    corresponding note would be helpful.

* getPosOut:

  - May this flush the stream (and hence raise Io exceptions)?

* setPosOut:

  - This may raise an exception because the position has been
    invalidated after obtaining it (e.g. by file truncation
    performed by another process).

  - Typo, s/underlying device/underlying writer/

* setBufferMode, getBufferMode:

  - There is no specification of the semantics of line buffering, in
    particular for non-text streams.
    (See also comments on StreamIO functor)

  - It is not specified whether the stream may be flushed when set
    to LINE_BUF mode (may cause Io exception). It seems unreasonable
    to require it not to do so (assuming that line buffering is
    intended to maintain the invariant that the buffer never
    contains line breaks).

  - The synopsis of this function uses "ostr", while all others
    use "f" for streams.

* setPosOut, setBufferMode, getWriter:

  - Can raise an exception if flushing fails.

* Discussion:

  - The statement that closing a stream just causes the
    not-yet-determined part of the stream to be empty should
    probably be generalised to explain what *truncating* a stream
    means (getReader also truncates the stream).

  - Example of freshly opened stream:
    s/mkInstream r/mkInstream(r, vector [])/
    s/size/length/

  - nreads example:
    s/mkInstream r/mkInstream(r, vector [])/
    s/size/length/

  - input1/inputN relation example:
    (1) Inconsistent with the actual typing of input1 (see above).

    (2) Typo, s/inputN f/inputN(f,1)/

  - Unbuffered I/O, 1st example:
    (1) Typos,
    s/mkInstream(reader)/mkInstream(reader, vector [])/
    s/PrimIO.Rd{chunkSize,...}/(PrimIO.RD{chunksize,...}, v)/

    (2) More importantly, the actual condition appears to be
    incorrect. It should read:
    (chunkSize > 1 orelse length v = 1) andalso endOfStream f'

  - Unbuffered I/O, 2nd example:
    s/mkInstream(reader)/mkInstream(reader, vector [])/
    s/PrimIO.Rd{chunkSize,...}/(PrimIO.RD{chunksize,...}, v)/
    The condition must be corrected as above.

* There is no reference to the StreamIO functor.



The StreamIO functor
--------------------

* General problems:

  - It is impossible for this functor to support line buffering,
    since it has no way of knowing which element consists a line
    break. This could be solved by changing the someElem functor
    argument to a breakElem argument.

  - It is also impossible to utilize reader's endPos for
    pre-allocation, because the functor is parametric in the
    position type.

* Functor argument:

  - Since the extract and copy functions have been removed/changed
    from ARRAY and VECTOR signatures, the StreamIO functor now
    naturally requires slice structures for efficient
    implementation. (Likewise the PrimIO functor)

* Functor result:

  - Type sharing of the result types is not specified.

* Discussion, paragraph on flushing:

  - Most of this discussion rather belongs to the description of
    STREAM_IO.

  - Everything said here is not restricted to flushOut, but applies
    to flushing in general.

  - Unfortunately, it is left unspecified where flushing may happen
    and, consequently, where respective Io exceptions may occur.

  - Write retries as suggested here seem to be impossible to
    implement correctly using the writer interface as specified (see
    comments on PRIM_IO.writer).

  - According to the writer description, write operations may never
    return an element count of 0, so the last sentence is
    misleading.

* Discussion, last paragraph:

  - Typo, missing ")"

* Implementation note:

  - 3rd bullet: typo, s/PrimIO.augmentIn/PrimIO.augmentReader/

  - 5th and 6th bullet: The endPos function cannot be utilized as
    suggested, because the functor is necessarily parametric in the
    position type.



The IMPERATIVE_IO signature
---------------------------

* General comment:

  - It is unfortunate that imperative I/O is asymmetric with respect
    to providing (limited) random access on input vs. output streams
    - the former requires going down to the lower-level stream I/O.
    That makes imperative I/O a somewhat incomplete abstraction
    layer.

  - Likewise, it would be desirable if there were ways for
    performing full-fledged random access without leaving the
    imperative I/O abstraction layer, at least for streams were it
    is suitable (e.g. BinIO). Despite the statement in the
    discussion this is neither available for input nor for output
    streams (see comments below).

* closeIn:

  - Typo, s/S.closeIn/StreamIO.closeIn/

* flushOut:

  - Typo, s/S.flushOut/StreamIO.flushOut/

* closeOut:

  - Typo, s/S.closeOut/StreamIO.closeOut/

* Discussion:

  - Equivalences, last line: s/StreamIO.output/StreamIO.flushOut/

  - Paragraph about random-access on output streams: It says that
    BinIO.StreamIO.out_pos = Position.int. This is not true, we have
    BinPrimIO.pos = Position.int, but that is a completely different
    type. In fact, it is impossible to implement out_pos as
    Position.int.

* There is no reference to the ImperativeIO functor.



The ImperativeIO functor
------------------------

* Functor argument:

  - The Array argument is unnecessary.

* Functor result:

  - Type sharing of the result types is not specified.



The TEXT_STREAM_IO signature
----------------------------

* General comment:

  - Why bother separating this signature from STREAM_IO?
    => outputSubstr can easily be generalised to outputSlice
       (for good),
    => if line buffering is part of STREAM_IO, inputLine
       might be as well.



The TextIO structure
--------------------

* General comment:

  - Systems providing WideText should also provide a WideTextIO
    structure (they have to provide WideTextPrimIO already, which
    seems inconsistent).

* Interface:

  - Duplicated type constraints for StreamIO.reader and
    StreamIO.writer.



The BinIO structure
--------------------

* Interface:

  - Type sharing with BinPrimIO is not specified (unlike for
    TextIO), i.e. the following constraints are missing:

        where type StreamIO.reader = BinPrimIO.reader
        where type StreamIO.writer = BinPrimIO.writer
        where type StreamIO.pos = BinPrimIO.pos

******************************************************************************
******************************************************************************
******************************************************************************
******************************************************************************

Doing host/network byte order conversions on ML side.

Socket.Ctl
* Semantics of setNBIO, getNREAD, getATMARK are unclear;
  Don't seem to be accessible via {get,set}sockopt;
  Instead, using ioctl.

******************************************************************************
******************************************************************************

Posix.FileSys:
* Within structure S, the type mode is constrained equal to flags,
  but flags is an eqtype.

STREAM_IO.pos
* "This is the type of positions in the underlying readers and
  writers. In some instantiations of this signature (e.g.,
  TextIO.StreamIO), pos is abstract; in others (e.g., BinIO.StreamIO)
  it is Position.int."  But, the equality of BinIO.StreamIO.pos and
  Position.int is never specified in any where constraint of BinIO.
* How can filePosIn be implemented with completely abstract pos?

Not sent to list:

* (In general, probably a good idea to look at the entire top-level
  structure/signature matches and choose a consistent usage of base
  types.  For example, Int:>INTEGER would seem to hide the top-level
  int; unless Int is opened afterwards.  But, then what about all the
  other structures that reference int?  Is top-level int = Int.int or
  is Int.int = top-level int.)
--> I think I'm biased from looking at the MLton implementation,
becuase I'm finding it hard to think about how to really express all
of the sharing constraints in a way that will be acceptable.  This
might be the wrong way to look at things: the listing of structures
and signatures with clauses doesn't correspond to a build order, it
corresponds to the way the environment should look to the program.

Sequences and Slices:
Why not existsi, alli?

Vector:
Why no vector: int * 'a -> 'a vector?


Resolved:

If one defines VECTOR_SLICE by including a type 'a vector and replace
'a Vector.vector with the local 'a vector, but then binds
structure Vector: VECTOR
structure VectorSlice: VECTOR_SLICE where type 'a vector = 'a Vector.vector
at the top-level, does one violate the basis spec?
Rationale: it's easiset to implement Vector and VectorSlice
simultaneously, say with VectorSlice as a substructure of Vector (in
fact, with all of the Vector operations being dispatched to the
corresponding VectorSlice ops with full slices), so Vector isn't in
scope for the VECTOR_SLICE.
*** No, it's not o.k., because opening VectorSlice will introduce a binding
    for 'a vector; but, if we're lucky, John will accept the proposal.

IEEEReal:
toString prepends a #"~" even when the class is NAN?
*** I guess this is o.k.; there is an explicit sign field.

PACK_WORD:
structure Pack<N>Big :> PACK_WORD  (* OPTIONAL *)
structure Pack<N>Little :> PACK_WORD  (* OPTIONAL *)
but PACK_WORD has
val subVec  : Word8Vector.vector * int -> LargeWord.word
i.e., reference to LargeWord.word.
Should it be
PACK_WORD
type word
val subVec  : Word8Vector.vector * int -> word
with
structure Pack<N>Big :> PACK_WORD with word = Word<N>.word  (* OPTIONAL *)
Should there be PackBig and PackLittle with word = Word.word?
Should there be PackLargeBig with word = LargeWord.word?
There aren't many structures that refine on LargeXYZ; most refine on XYZ<N>.
*** O.k., we always unpack into a LargeWord, which we could then
    Word<N>.fromLargeWord back to the size.  I guess this is o.k.; It
    lets an implementation give more Pack<N>Big structures than there
    are Word<N> structures.

MLton specific:
 + why are Int32_gtu and Int32_geu primitive?
   Why not just Word.fromInt and use Word comparisons?
 + Real:>REAL doesn't match basis because it may peform
    arithmetic at extended precision.  Should this be mentioned
    in the user guide?
 + QUESTION: proc-env.sml
 + QUESTION: char.sml
 + check uses of {Vector,Array}Slice.slice for replacement by unsafeSlice.


******************************************************************************
******************************************************************************

UNIX:
I'm not quite sure how the ('a, 'b) proc type is supposed to work in
practice; The old Unix structure just used them as
TextIO.{in,out}streams.  My suspicion is that we're supposed to use
Posix.IO.mk{Bin,Text}{Reader,Writer} functions and then use the type
system to ensure that if we force a stream to be bin or text, then all
other uses have to be the same.  I also suspect that we're only
supposed to lift the file_desc up to an instream/outstream once; i.e.,
multiple textInstreamOf calls should continue to return the same
TextIO.instream.  That would seem to suggest we need an 'a option ref
that can be banged at the first call to a streamOf function, and
subsequent calls just return the value there.

textInstreamOf pr
binInstreamOf pr
    return a text or binary instream connected to the standard output
    stream of the process pr. Note the multiple calls to these
    functions on the same proc will result in multiple streams that
    all share the same underlying Unix stream.

textOutstreamOf pr
binOutstreamOf pr
    return a text or binary outstream connected to the standard input
    stream of the process pr. Note the multiple calls to these
    functions on the same proc will result in multiple streams that
    all share the same underlying Unix stream.

streamsOf pr
    returns a pair of input and output text streams associated with
    pr. This function is equivalent to (textInstream pr, textOutstream
    pr) and is provided for backward compatibility.