-
Notifications
You must be signed in to change notification settings - Fork 0
/
SRFI-105.html
2477 lines (2326 loc) · 105 KB
/
SRFI-105.html
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
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>SRFI 105: Curly-infix-expressions</title>
<meta content="text/html; charset=us-ascii" http-equiv="content-type">
</head>
<body>
<!-- This commented out text is for the brittle SRFI tools -->
<!--
<H1>Title</H1>
Curly-infix-expressions
<H1>Author</H1>
David A. Wheeler, Alan Manuel K. Gloria
<H1>Status</H1>
This SRFI is in ``final'' status.
-->
<h1 id="title">Title</h1>
<p>Curly-infix-expressions</p>
<h1 id="author" id="authors">Authors</h1>
<p><a href="http://www.dwheeler.com">David A. Wheeler</a></p>
<p>Alan Manuel K. Gloria</p>
<h1 id="status">Status</h1>
<p>
This SRFI is in ``final'' status. To see an explanation of
each status that a SRFI can hold, see <a
href="http://srfi.schemers.org/srfi-process.html">here</a>.
To provide input on this SRFI, please
<a href="mailto:srfi minus 105 at srfi dot schemers dot org">mail to
<code><srfi minus 105 at srfi dot schemers dot org></code></a>. See
<a href="../srfi-list-subscribe.html">instructions here</a> to
subscribe to the list. You can access previous messages via
<a href="mail-archive/maillist.html">the archive of the mailing list</a>.
You can access
post-finalization messages via
<a href="http://srfi.schemers.org/srfi-105/post-mail-archive/maillist.html">
the archive of the mailing list</a>.
</p>
<ul>
<li>
Received: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.2">2012/08/22</a></li>
<li>Draft: 2012/08/22-2012/10/22</li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.3">2012/09/03</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.4">2012/09/08</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.5">2012/09/17</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.6">2012/09/19</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.7">2012/09/27</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.8">2012/10/02</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.9">2012/10/15</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.10">2012/10/16</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.11">2012/10/20</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.12">2012/10/21</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.13">2012/10/25</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.14">2012/10/27</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.15">2012/10/30</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.16">2012/10/31</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.17">2012/11/01</a></li>
<li>Revision: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.18">2012/11/01</a></li>
<li>Finalized: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-105/srfi-105.html?rev=1.19">2012/11/01</a></li>
</ul>
<h1><a name="related-srfis">Related SRFIs</a></h1>
<p>None</p>
<h1><a name="abstract">Abstract</a></h1>
<p>Lisp-based languages, like Scheme, are almost the only
programming languages in modern use that do not support infix notation.
In addition, most languages allow infix expressions to be combined
with function call notation of the form
<code><var>f</var>(<var>x</var>)</code>.
This SRFI provides these capabilities, both for
developers who already use Scheme and want these conveniences,
and also for other developers who may choose to use other languages
in part because they miss these conveniences.
Scheme currently reserves <code>{</code>...<code>}</code>
“for possible future extensions to the language”.
We propose that <code>{</code>...<code>}</code> be used
to support “curly-infix-expression” notation as a homoiconic
infix abbreviation,
as a modification of the Scheme reader.
It is an abbreviation in much the same way that
<samp>'x</samp> is an abbreviation for <samp>(quote x)</samp>.
</p>
<p>
A
<a href="#specification"><dfn>curly-infix list</dfn></a>
introduces a list whose visual presentation
can be in infix order instead of prefix order.
For example,
<samp>{n > 5}</samp> ⇒ <samp>(> n 5)</samp>,
and
<samp>{a + b + c}</samp> ⇒
<samp>(+ a b c)</samp>.
By intent, there is no precedence, but e.g.,
<samp>{x + {y * z}}</samp>
maps cleanly to
<samp>(+ x (* y z))</samp>.
Forms with mixed infix operators and other complications have
“<code>$nfx$</code>” prepended to
enable later processing, e.g.,
<samp>{4 + 5 * 6}</samp> ⇒
<samp>($nfx$ 4 + 5 * 6)</samp>.
Also, inside a curly-infix list (recursively),
expressions of the form <code><var>f</var>(</code>...<code>)</code> are simply
an abbreviation for <code>(<var>f</var> </code>...<code>)</code>.</p>
<p>Note that this is derived from the
“<a href="http://readable.sourceforge.net/">readable</a>”
project.
We intend to later submit at least one additional SRFI that will build on
top of this SRFI, but curly-infix-expressions are useful on their own.
</p>
<h1><a name="rationale">Rationale</a></h1>
<p>Lisp-based languages, like Scheme, are almost the only
programming languages in modern use that do not support infix
notation. Even some Lisp advocates, like Paul Graham, admit that
they “don’t find prefix math expressions
natural” (<a href="http://www.paulgraham.com/popular.html"
rel="nofollow">http://www.paulgraham.com/popular.html</a>) even after
decades of experience with Lisp-based languages.
Paul Prescod has said, “I have more faith that you could convince
the world to use Esperanto than prefix notation”
(<a href="http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg01571.html" rel="nofollow">http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg01571.html</a>).
Infix is not going away; standard mathematical notation uses infix,
infix notation is taught to most people (programmers or not) in school,
and nearly all new programming languages include infix.
</p>
<p>
Adding infix support to Scheme would be a useful convenience for
some existing developers who use Scheme, and it would also
eliminate a common complaint
by developers who currently choose to use other languages instead.
</p>
<p>Scheme currently reserves
<code>{</code>...<code>}</code> “for possible future
extensions to the language”. We propose that
<code>{</code>...<code>}</code> be used to
support “curly-infix-expression” notation as a reader
abbreviation, just as
<samp>'x</samp> is an abbreviation for <samp>(quote x)</samp> and
<samp>(x y z)</samp>
is an abbreviation for
<samp>(x . (y . (z . ())))</samp>.
</p>
<p>This proposal is an extremely <em>simple</em> and
<em>straightforward</em> technique for supporting infix notation.
There is no complex precedence system, all other Scheme
capabilities (including macros and quasiquoting) work unchanged,
any symbol can be used as an infix operation where desired,
and Scheme remains general and homoiconic.
Curly-infix-expressions (also known as c-expressions)
are just a convenient reader abbreviation for infix notation.</p>
<p>At its core, this SRFI provides
the <em>simple</em> curly-infix list,
a list whose visual presentation is in infix order instead of prefix order.
The simple curly-infix list
<samp>{<var>operand-1</var> <var>operator</var> <var>operand-2</var> <var>operator</var> <var>operand-3</var> <var>operator</var> </samp>...<samp>}</samp>
is mapped to
<samp>(<var>operator</var> <var>operand-1</var> <var>operand-2</var> <var>operand-3</var> </samp>...<samp>)</samp> so that two or
more operands are handled cleanly.
E.g., <samp>{a + b + c}</samp> ⇒
<samp>(+ a b c)</samp>.</p>
<p>
More examples of c-expressions and their mappings are given below in the
<a href="#specification">specification</a>.
See the <a href="#design-rationale">design rationale</a>
for details on why the notation is designed the way it is.
</p>
<!--
Note the hyphenation convention:
curly-infix-expression(s) == c-expression(s)
curly-infix list
curly-infix reader
-->
<h1><a name="specification">Specification</a></h1>
<p>
The key words
“<em>MUST</em>”,
“<em>MUST NOT</em>”,
“<em>REQUIRED</em>”,
“<em>SHALL</em>”,
“<em>SHALL NOT</em>”,
“<em>SHOULD</em>”,
“<em>SHOULD NOT</em>”,
“<em>RECOMMENDED</em>”,
“<em>MAY</em>”,
and “<em>OPTIONAL</em>” in this
document are to be interpreted as described in
<a href="http://www.ietf.org/rfc/rfc2119.txt">RFC 2119</a>.
</p>
<p>“<dfn>Curly-infix-expressions</dfn>” (aka “<dfn>c-expressions</dfn>”) are
s-expressions with an additional supported notation:
The curly-infix list.
A curly-infix list is syntactically almost identical to a regular list,
but it is surrounded by a matched pair of braces instead of by a pair of parentheses, and instead of
a sequence of s-expressions it contains a sequence of
neoteric-expressions (which add support for formats like
<code><var>f</var>(<var>x</var>)</code>).
Once a curly-infix list is read, it is mapped differently than a
regular list by a curly-infix reader:</p>
<ol>
<li>A <dfn>simple</dfn> curly-infix list has an odd number of
parameters, at least three parameters, and all even parameters are
“<code>equal?</code>”.
If there is more than one even parameter, and
an even parameter contains a cycle, then
the <code>equal?</code> comparison <em>MUST</em> terminate
if <code>equal?</code> terminates (otherwise
the comparison <em>MAY</em> terminate).
A simple curly-infix list is mapped by
the reader into a list with the first even parameter
followed by the odd parameters.
E.g.,
<samp>{n <= 5}</samp> ⇒
<samp>(<= n 5)</samp>,
and
<samp>{4 * 5 * 6}</samp> ⇒
<samp>(* 4 5 6)</samp>.</li>
<li>The <dfn>empty</dfn> curly-infix list
<code>{}</code> is mapped to the empty list <code>()</code>.
An implementation <em>MUST</em> permit, and not require,
whitespace between the braces in an empty curly-infix list.</li>
<li>An <dfn>escaping</dfn> curly-infix list
<code>{<var>e</var>}</code> is mapped to <code><var>e</var></code>.
E.g., <samp>{5}</samp> ⇒ <samp>5</samp>.</li>
<li>A <dfn>unary-operation</dfn> curly-infix list
<code>{<var>e1</var> <var>e2</var>}</code>
is mapped to
<code>(<var>e1</var> <var>e2</var>)</code>.
E.g.,
<samp>{- x}</samp> ⇒
<samp>(- x)</samp>.</li>
<li>The mapping of a curly-infix list beginning with the symbol
“<code>.</code>” is unspecified.
(Note: the reference implementation maps
<code>{. <var>e</var>}</code> to <code><var>e</var></code>.)
</li>
<li>Any other curly-infix list (including all other improper lists) is
<dfn>mixed</dfn>. A mixed curly-infix list <em>MUST</em> be mapped to that list with “<code>$nfx$</code>” added to its front.
E.g.,
<samp>{q + r * s}</samp>
⇒
<samp>($nfx$ q + r * s)</samp>, and
<samp>{q + r . s}</samp>
⇒
<samp>($nfx$ q + r . s)</samp>.
</li>
</ol>
<p>
Here is the syntax of a curly-infix list
(which is nearly identical to a traditional list):
</p>
<!--
Note: CSS "style" is not included in HTML 3.2, so we'll use
a table to force a reasonable format.
-->
<table>
<tr valign="top">
<td>curly‑infix‑list →</td>
<td>“<tt>{</tt>”
<whitespace>*
[ <n-expression>
[ <whitespace>+ <n-expression> ]*
[ <whitespace>+ <b>.</b>
<whitespace>+ <n-expression> ]
<whitespace>* ]
“<tt>}</tt>”
</td>
</tr>
</table>
<p>
A “<dfn>neoteric-expression</dfn>” (aka “<dfn>n-expression</dfn>”)
is a curly-infix-expression, with the following additional syntaxes
and mappings
for a datum (where <var>e</var> is any datum expression):
</p>
<ol>
<li>
<code><var>e</var>(</code>...<code>)</code> ⇒
<code>(<var>e</var> </code>...<code>)</code>.
E.g.,
<samp>cos(x)</samp> ⇒
<samp>(cos x)</samp>,
<samp>f(a b)</samp> ⇒
<samp>(f a b)</samp>,
<samp>exit()</samp> ⇒
<samp>(exit)</samp>, and
<samp>read(. options)</samp> ⇒
<samp>(read . options)</samp>.</li>
<li>
<code><var>e</var>{}</code> ⇒ <code>(<var>e</var>)</code>
when there are zero or more whitespace characters
within the braces;
otherwise,
<code><var>e</var>{</code>...<code>}</code> ⇒ <code>(<var>e</var> {</code>...<code>})</code>.
E.g.,
<samp>f{n - 1}</samp>
⇒
<samp>(f {n - 1})</samp>
⇒
<samp>(f (- n 1))</samp>,
and
<samp>g{- x}</samp>
⇒
<samp>(g (- x))</samp>.</li>
<li><code><var>e</var>[</code>...<code>]</code> ⇒
<code>($bracket-apply$ <var>e</var> </code>...<code>)</code></li>
<li>The above mappings <em>MUST NOT</em> be applied
if one or more whitespace characters are present between <var>e</var> and the open
paired character.</li>
<li>An unprefixed <code>( . <var>e</var>)</code> <em>MUST</em> map to <code><var>e</var></code>.</li>
<li>
These <em>MUST</em> recurse within lists and vectors,
so any list or vector
in a position that accepts a neoteric expression
<em>MUST</em> accept a sequence
of zero or more <em>neoteric</em> expressions,
not just s-expressions.
(Note that this occurs if they are directly or indirectly
within a curly-infix list or a neoteric-expression.)
Any other implementation-specific constructs
in a position that accepts a neoteric expression
<em>SHOULD</em> accept neoteric-expressions within it.
</li>
<li>
These <em>MUST</em> recurse left-to-right.
E.g.,
<samp>f{n - 1}(x)</samp>
⇒
<samp>(f {n - 1})(x)</samp>
⇒
<samp>(f (- n 1))(x)</samp>
⇒
<samp>((f (- n 1)) x)</samp>
</li>
</ol>
<p>
Where datum comments are supported using <samp>#;</samp>,
datum comments <em>SHOULD</em> comment the datum as defined above.
(Datum comments are defined in SRFI-62; they are also included in
R6RS and R7RS draft 6.)
Note that any s-expression is also an n-expression,
because n-expressions include c-expressions
and c-expressions include s-expressions.
</p>
<p>Here are some examples of c-expressions (note that all operators
in curly-infix-expressions are delimited):</p>
<ol>
<li><samp>{n <= 5}</samp> ⇒
<samp>(<= n 5)</samp></li>
<li><samp>{x + 1}</samp>
⇒
<samp>(+ x 1)</samp></li>
<li><samp>{a + b + c}</samp>
⇒
<samp>(+ a b c)</samp></li>
<li><samp>{x ,op y ,op z}</samp> ⇒
<samp>(,op x y z)</samp></li>
<li><samp>{x eqv? `a}</samp> ⇒ <samp>(eqv? x `a)</samp></li>
<li><samp>{'a eq? b}</samp> ⇒ <samp>(eq? 'a b)</samp></li>
<li>
<samp>{n-1 + n-2}</samp>
⇒
<samp>(+ n-1 n-2)</samp>
</li>
<li><samp>{a * {b + c}}</samp> ⇒ <samp>(* a (+ b c))</samp></li>
<li>
<samp>{a + {b - c}}</samp>
⇒
<samp>(+ a (- b c))</samp>
</li>
<li>
<samp>{{a + b} - c}</samp>
⇒
<samp>(- (+ a b) c)</samp>
</li>
<li><samp>{{a > 0} and {b >= 1}}</samp> ⇒
<samp>(and (> a 0) (>= b 1))</samp></li>
<li>
<samp>{}</samp>
⇒
<samp>()</samp>
</li>
<li>
<samp>{5}</samp>
⇒
<samp>5</samp>
</li>
<li>
<samp>{- x}</samp>
⇒
<samp>(- x)</samp>
</li>
<li>
<samp>{length(x) >= 6}</samp>
⇒
<samp>(>= (length x) 6)</samp></li>
<li>
<samp>{f(x) + g(y) + h(z)}</samp>
⇒
<samp>(+ (f x) (g y) (h z))</samp>
</li>
<li><samp>{(f a b) + (g h)}</samp> ⇒ <samp>(+ (f a b) (g h))</samp></li>
<li><samp>{f(a b) + g(h)}</samp> ⇒ <samp>(+ (f a b) (g h))</samp> as well</li>
<li><samp>'{a + f(b) + x}</samp> ⇒ <samp>'(+ a (f b) x)</samp></li>
<li><samp>{(- a) / b}</samp> ⇒ <samp>(/ (- a) b)</samp></li>
<li><samp>{-(a) / b}</samp> ⇒ <samp>(/ (- a) b)</samp> as well</li>
<li><samp>{cos(q)}</samp> ⇒ <samp>(cos q)</samp></li>
<li>
<samp>{e{}}</samp> ⇒
<samp>(e)</samp>
</li>
<li>
<samp>{pi()}</samp> ⇒
<samp>(pi)</samp>
</li>
<li><samp>{'f(x)}</samp> ⇒ <samp>'(f x)</samp></li>
<li><samp>{#1=f(#1#)}</samp> ⇒ <samp>#1=(f #1#)</samp>
if there is support for the SRFI-38 external representation
for data with shared structure</li>
<li>
<samp>{ (f (g h(x))) }</samp>
⇒
<samp>(f (g (h x)))</samp>
... note that this is not
<samp>(f (g h (x)))</samp>
</li>
<li>
<samp>{#(1 2 f(a) 4)}</samp>
⇒
<samp>#(1 2 (f a) 4)</samp></li>
<li>
<samp>{(f #;g(x) h(x))}</samp>
⇒
<samp>(f (h x))</samp>
if datum comments are supported... note that this is not
<samp>(f (x) (h x))</samp>
</li>
<li>
<samp>{(map - ns)}</samp>
⇒
<samp>(map - ns)</samp>
</li>
<li>
<samp>{map(- ns)}</samp>
⇒
<samp>(map - ns)</samp> as well
</li>
<li>
<samp>{n * factorial{n - 1}}</samp>
⇒
<samp>(* n (factorial (- n 1)))</samp>
</li>
<li>
<samp>{2 * sin{- x}}</samp>
⇒
<samp>(* 2 (sin (- x)))</samp>
</li>
<li>
<samp>{3 + 4 +}</samp>
⇒
<samp>($nfx$ 3 + 4 +)</samp>
</li>
<li>
<samp>{3 + 4 + 5 +}</samp>
⇒
<samp>($nfx$ 3 + 4 + 5 +)</samp>
</li>
<li>
<samp>{a . z}</samp>
⇒
<samp>($nfx$ a . z)</samp>
</li>
<li>
<samp>{a + b - c}</samp>
⇒
<samp>($nfx$ a + b - c)</samp>
</li>
<li>
<samp>{read(. options)}</samp> ⇒
<samp>(read . options)</samp>
</li>
<li>
<samp>{a(x)(y)}</samp>
⇒
<samp>((a x) y)</samp>
<li>
<samp>{x[a]}</samp>
⇒
<samp>($bracket-apply$ x a)</samp>
</li>
<li>
<samp>{y[a b]}</samp>
⇒
<samp>($bracket-apply$ y a b)</samp>
</li>
<li>
<samp>{f{n - 1}(x)}</samp>
⇒
<samp>((f (- n 1)) x)</samp>
</li>
<li>
<samp>{f{n - 1}{y - 1}}</samp>
⇒
<samp>((f (- n 1)) (- y 1))</samp>
</li>
<li>
<samp>{f{- x}[y]}</samp>
⇒
<samp>($bracket-apply$ (f (- x)) y)</samp>
</li>
</ol>
<p>A <dfn>curly-infix reader</dfn> is a datum reader
that can correctly read and map curly-infix-expressions.
A curly-infix reader <em>MUST</em>
include the braces “<code>{</code>” and
“<code>}</code>” as delimiters.</p>
<p>
An implementation of this SRFI <em>MUST</em> accept
the marker <code>#!curly-infix</code> followed by a whitespace character
in its standard datum readers (e.g., <code>read</code> and, if applicable,
the default implementation REPL).
This marker (including the trailing whitespace character)
<em>MUST</em> be consumed and considered whitespace.
After reading this marker, the reader <em>MUST</em> accept
curly-infix-expressions in subsequent datums
read from the same port until some other conflicting marker is given
(no conflicting marker is specified here).
</p>
<p>
Implementations of this SRFI <em>SHOULD</em>
implement curly-infix-expressions in their datum readers by default,
even when the marker is not received.
Portable applications <em>SHOULD</em> include this marker before
using curly-infix-expressions, typically near the top of a file.
Portable applications <em>SHOULD NOT</em>
use this marker as the very first characters
of a file (e.g., it could be preceded by a newline),
because they might be misinterpreted on some platforms
as an executable script header.
</p>
<p>
An implementation <em>MUST NOT</em>
bind the symbols
“<code>$nfx$</code>” or
“<code>$bracket-apply$</code>”
by default to a procedure, macro, or syntax
that <em>cannot</em> be overridden.
An implementation <em>SHOULD NOT</em> bind the symbols
“<code>$nfx$</code>” or
“<code>$bracket-apply$</code>”
to a procedure, macro, or syntax in the
default environment, with the exception that it
<em>MAY</em> bind them by default to something that produces an error.
These two symbols are reserved for use by library writers
(in the case of a library-based implementation of this SRFI,
these symbols are
reserved for use by <em>other</em> libraries)
and application writers.
</p>
<p>
<em>However</em>, an implementation <em>MAY</em>
provide one or more
<em>libraries</em> that when imported
bind the “<code>$nfx$</code>” and/or
“<code>$bracket-apply$</code>”
symbols
(as it is then a library, this case actually falls under
the “reserved for use by library writers” clause above).
Application writers and other library writers
using that implementation are then free to use or not use
the implementation’s provided
“<code>$nfx$</code>” and/or
“<code>$bracket-apply$</code>”
as provided by those libraries.
</p>
<p>
Implementations <em>MAY</em> provide the procedure
<var>curly-infix-read</var> as a
curly-infix reader.
If provided, this procedure
<em>SHOULD</em> support an optional port parameter.
</p>
<p>
Security implication: If the implementation does not check for
circularity when doing equality comparisons, and a supplier of
malicious data can specify a circularity,
the reader could fail to terminate when comparing infix operators.
In the worst case this could cause a denial of service.
A solution is to check for circularity when comparing operators.
</p>
<p>Note that, by definition, this SRFI modifies lexical syntax.</p>
<h1><a name="design-rationale">Design Rationale</a></h1>
<p>
This SRFI design
rationale is unusually long, especially when you compare it to
the simplicity of its specification.
However, the notation described in this SRFI builds on the
lessons learned from the many previous infix mechanisms that have been
developed for Scheme and related Lisp-based languages.
The authors believe that it is important to document why various
decisions were made, in particular, to show why this approach is
an improvement over past approaches and more likely to gain wide acceptance.
We have separated the design rationale from the overall rationale,
as was previously done by SRFI-26, because it is easier to
understand the design rationale after reading the specification.
</p>
<h2><a name="rationale_changereader">Why not macros? Why modify the reader?</a></h2>
<p>Many previous systems have implemented “infix”
systems as a named macro or procedure (e.g., <code>INFIX</code>).
This looks ugly, and it does the wrong thing — the resulting list
always has <code>INFIX</code> at the beginning,
not the actual infix operator, so this
approach can interfere with quoting, macros, and other capabilities.
In particular,
consider the following <code>syntax-rules</code> macro
for function composition:
</p>
<pre>
(define-syntax o
(syntax-rules ()
({f o g}
(lambda args
(f (apply g args))))
({f o g o h o ...}
{(lambda (x)
(f (g x))) o h o ...})))
</pre>
<p>
This example takes advantage of the fact that
<samp>{f o g o h o ...}</samp>
⇒ <samp>(o f g h ...)</samp>.
Infix cannot be implemented as a macro alone,
as the <code>syntax-rules</code> form has
a particular treatment for the pattern.
A macro for infix would very likely confuse
the <code>syntax-rules</code> form.
</p>
<p>
A reader notation that
maps to a simple and obvious s-expression structure
also allows
notations such as
<samp>(map . {as + bs})</samp>
⇒
<samp>(map + as bs)</samp>.
For example,
in combination with
<a href="http://srfi.schemers.org/srfi-26/srfi-26.html">SRFI-26</a>,
you can express
templated procedures:
<samp>(cut . {<> < 42})</samp>
</p>
<h2><a name="rationale_braces">Why use brace characters for infix?</a></h2>
<p>
There is no perfect character, but braces (aka curly braces) are pretty close.
A key issue is that you want a balanced pair of characters to identify infix,
since you can have infix-in-infix.
The curly braces are visually pleasant pairs, so
it makes sense to use these precious characters on something
extremely common: infix notation.
</p>
<p>
All other character pairs other than braces have serious problems.
Parentheses are already spoken for, of course.
R6RS Scheme already uses up square brackets as a synonym for parentheses.
Angle brackets are already used for comparison.
Paired characters outside the ASCII set have other problems:
some Schemes do not support characters outside the ASCII character set,
such characters are not as well supported by other tools
(and are sometimes corrupted by such tools),
they are more complicated to deal with due to
character encoding problems, and they are harder to enter on many keyboards.
</p>
<p>
In contrast, curly braces are in the ASCII character set and are
already available for this purpose.
They do not have a standardized meaning in any Scheme specification.
They are also widely available in many other Lisp-derived languages,
such as Common Lisp
(as we’d like this notation to be widely useful across Lisps,
even beyond Scheme).
</p>
<p>
Although curly braces <em>can</em> be used as local Scheme extensions,
there are few Scheme implementations which do so.
On
<a href="http://srfi.schemers.org/srfi-105/mail-archive/msg00063.html">
September 5, 2012, John Cowan posted</a> the
<a href="http://trac.sacrideo.us/wg/wiki/BracketsBraces">results</a>
analyzing the
meanings of square brackets and curly braces in his Scheme test suite
(of 45 Scheme implementations).
Only 2 (Chibi and RScheme) of 45 currently do something
special with braces; “the other implementations treat them
as either synonyms for parentheses, lexical syntax errors,
or identifier characters”.
That is a remarkably small number of Scheme implementations where this
use of curly braces would conflict with some special semantic.
Donovan Kolbly reported that
“RScheme uses braces to delimit C code embedded in Scheme code...
that said, a scanner hack could
easily mode-switch to SRFI-105 interpretation where needed.”
The Chibi extension using braces can be added or removed through a
compile-time option, so not even all Chibi executables have a
conflicting use of brace characters.
</p>
<p>
It’s true that <code>{</code>...<code>}</code> are often used in math for set notation. But
infix notation is far more basic, and common, than sets.
Also, traditional function call notation and infix are helpful when working
with sets, so infix notation is the more important need.
Once you allow neoteric-expressions,
the notation <code>set(</code>...<code>)</code> is a reasonable alternative.
</p>
<h2><a name="rationale_notdifferentsyntax">Why not use a completely different notation inside the expression?</a></h2>
<p>
Some past systems have built infix notations into the reader
in which the infix notation was radically different from normal Lisp notation.
For example, the symbol for procedure calls might change, the names of
variables or procedures might be spelled differently (at least in some cases),
and so on.
The result, in some cases, would be that these notations would
simultaneously lose Lisp’s abilities for
quoting, quasiquoting, and so on, and these notations were
not homoiconic.
It may become impossible to refer to certain symbols, since their
names might include a character that is interpreted as an infix operator.
They can also be confusing; the same symbols (e.g., parentheses) would have
a completely different meaning inside and outside the parentheses.
</p>
<p>
In contrast, this curly-infix-expression proposal avoids these problems.
The syntax for list creation, quasiquotation, and so on is almost
identical in a curly-infix-expression when compared to traditional notation.
For example, in curly-infix-expressions,
<samp>`{,a + ,b}</samp>
maps cleanly to
<samp>`(+ ,a ,b)</samp>,
which works as expected with all macros.
The main difference is that, in a curly-infix-expression, the position of
the operator in its surface syntax may be in a different location (infix)
than its actual final location.</p>
<h2><a name="rationale_noautodetect">Why not autodetect infix?</a></h2>
<p>Some past efforts tried to automatically detect infix operators,
but this turns out to not work well. It’s hard to express
good rules for detecting infix operators, and the rules become too
complex for users (e.g., “punctuation-only symbols”
doesn’t detect “<code>and</code>” or “<code>or</code>”).
And in
any case, if they were automatically detected, an escape mechanism
would be needed anyway -
consider <samp>(map - ns)</samp>
for getting a new list with
the numbers in <var>ns</var> negated.
Allowing the user to expressly notate when
infix was intended, using <code>{</code>...<code>}</code>,
turns out to be clearer
and more intuitive. In particular, curly-infix-expressions allow the use of
infix with any symbol, whenever you want... and where it’s
not convenient, you don’t need to use it. It is also very
backwards-compatible: Normal lists work normally, and if you want
infix, use <code>{</code>...<code>}</code>.</p>
<h2><a name="rationale_equal">Why use <code>equal?</code> to compare operators in a “simple” curly-infix list for equality?</a></h2>
<p>
Operators are compared using <code>equal?</code> so that
constructs like <samp>,op</samp> are legal operators,
e.g., <samp>{x ,op y ,op z}</samp>.
Note that unfortunately if the operator construct contains a cycle, it might not terminate
if <code>equal?</code> does not terminate in the presence of cycles.
This was specified this way so that implementers
could use the normal Scheme <code>equal?</code> comparison instead of
having to implement a special comparison operator just for this
particular case.
</p>
<h2><a name="rationale_delimiters">Why must infix operators be delimited?</a></h2>
<p>Curly-infix lists require that the infix operators be delimited (e.g., by
spaces). This is consistent with Lisp history and current practice.
Currently, in Lisp, operators are always
delimited in traditional s-expressions (typically by left
parentheses on the left, and by whitespace on the right).
It’s impractical to do otherwise today; most Lisps,
including Scheme, allow and predefine symbols that include characters (like
“<code>-</code>”) that are typically used for infix operators.
If infix operators were not delimited, it would be impractical or
complicated to refer to standard Scheme identifiers.
By requiring delimiters (as is already true for the rest of Scheme),
any procedure may be used as an infix operator, not just a fixed list.
Many developers put space around infix operators even in languages
that don’t require them, so syntactically requiring them is no burden.
There are even other existing languages
that also require infix operators be delimited,
such as SNOBOL4,
<a href="http://users.rcn.com/david-moon/PLOT/page-20.html">PLOT</a>,
and
<a href="http://www.rebol.com/docs/expert-intro.html">REBOL</a>.
In short, it is difficult to allow infix operators
without delimiters, and the visual results are the same as many
real-world uses in other languages, so the result appears quite
customary to typical software developers.</p>
<h2><a name="rationale_noprecedence">Why isn’t precedence part of this SRFI?</a></h2>
<p>Many past “infix” systems for Lisp build in
precedence. However, Lisp systems often process other languages,
and they may freely mix these different languages.
Thus, the same symbol may have different meanings
and precedence levels in different contexts.
The symbol might not even be defined where it is being
used, and allowing precedence definitions would create subtle errors
if files are read in a different order.
If users hook in their own precedence system into a reader, it could
even become difficult to combine code written for different precedence systems.
In short, building precedence into a
Lisp reader creates many complexities.</p>
<p>Yet the complexity of precedence systems is often unnecessary.
In practice, we’ve found that simple infix is all
that’s needed most of the time in Lisp-based languages.
Even in other languages, many developers unnecessarily use
grouping symbols with infix operators to make their order clear.
An examination of two Scheme programs written using curly-infix-expressions
(posted 2012-09-14) found that 55/78 (71%) of the top-level
c-expressions do not embed an opening brace; this means that precedence
is irrelevant for more than two-thirds of these top-level c-expressions.
Thus, requiring grouping symbols is less of a
hardship than it might appear.</p>
<p>
In addition, there is some experimental evidence that developers
(1) rarely use precedence rules and
(2) often apply them incorrectly.
The paper
<a href="http://www.knosof.co.uk/cbook/accu06.html">
“Developer beliefs about binary operator precedence (part 1)”
by Derek M. Jones</a> documents analysis of developer use and
understanding of precedence rules:
</p>
<ul>
<li>
They first measured the visible source code of a number of
large C programs (e.g., gcc, idsoftware, Linux, netscape,
openafs, openMotif, and postgresql).
Once they excluded operations not normally considered binary operators
(array subscript, function call, direct and indirect member
selection, and the assignment operators), they found that only
1.9% of all expressions had at least two binary operators
(where precedence would make a difference).
Of the expressions with at least one binary operator,
74% (more than two-thirds)
had only one binary operator - yet only expressions with more than one
could possibly benefit from precedence.
(Note that this is similar to the 71% result above.)
<!-- See table .1; the 1.9% = 100-92.82-5.25.
The 74% = 1-1.9/(5.28+1.9) = 0.73537604456824512 -->
In those cases where precedence could have been used
(the 1.9% of all expressions), 67%
(102,822/154,575) of the operator pairs were explicitly parenthesized
(making any precedence rule moot).
</li>
<li>
The authors then described a survey of developers
at the 2006 ACCU conference to determine if they correctly applied
the precedence and associativity of
the binary operators common to C, C++, C#, Java, Perl, and PHP.
In this experiment only 66.7% of the answers were correct (standard
deviation 8.8, poorest performer 45.2% correct, best performer 80.5% correct);
this was not much better than random chance (50%).
Even many widely-used operator pairs had relatively poor results;
only 94% of the problems were correctly solved when they combined
<code>*</code> and <code>+</code>,
92% when they combined <code>*</code> and <code>-</code>,
and 69% when they combined <code>/</code> and <code>+</code>.
These were far short of the 100% one might expect.
These developers ranged from 5 to 25 years of professional experience,
and the more-experienced developers did not do better (!).
It is possible that a different sample would produce
a higher percentage of correct answers.
Nevertheless, these results clearly suggest that precedence rules may harm,
instead of help, the process of developing correct code.
</li>
</ul>
<p>By intentionally <em>not</em>
building a precedence system into the reader,
a very simple yet useful infix system results.
We don’t need to register procedures, ensure that declarations
of precedence precede their use, gain widespread agreement on some
precedence order, or anything like it.
We also ensure that the notation is clearly homoiconic.</p>
<p>Instead, where precedence is desired, application and library writers
can implement precedence by defining and controlling the scope of an
“<code>$nfx$</code>” macro or procedure, or by later postprocessing
of that symbol.
Scheme macros are already quite powerful and capable of handling this;
in these cases, <code>{</code>...<code>}</code> provides a more
convenient notation.
The curly-infix-expression approach, instead of trying to manage both infix
and precedence, handles simple cases and then
takes advantage of the existing Scheme scoping rules and macro system for
more complex cases (in the rare cases where they are needed).</p>
<p>Note that curly-infix-expressions
include support for unary operators, but again,
they are without precedence.
As a result, they must be grouped separately.
This does not lead to hard-to-read expressions, however.
Examples of simple curly-infix lists combining infix and unary operations
include
<samp>{-(x) * -(y)}</samp>
and
<samp>{-{x} * -{y}}</samp>
(the notation is designed so that both work).
</p>
<p>At first <a href="http://www.dwheeler.com">David A. Wheeler</a>,
who started this project,
considered reporting an error if a simple infix
expression isn’t provided.
However, prepending “<code>$nfx$</code>”
is much more flexible.</p>
<h2><a name="rationale_precedence_addable">Could precedence be added?</a></h2>
<p>It would be <em>possible</em>
to extend curly-infix-expressions to provide a fixed
precedence system (e.g., if an expression is mixed,
attempt to use various precedence rules).
Here is a discussion how this could be accomplished in the future
(should that be necessary), which may also show why such systems were
not proposed in this SRFI.
It is important to understand that
such capabilities would be extensions <em>beyond</em> this SRFI.
</p>
<p>
It would be best if the precedence rules (if any) were absolutely fixed;
otherwise, subtle bugs would happen if only some files were read after the
precedence was declared, and code would be hard to correctly combine
and move if different code sections used different precedence rules.
However, the precedence rules can be fixed while still allowing
arbitrary new symbols, as shown below.
</p>
<p>
Unfortunately, there would be substantial arguments about the semantics
(including the operators and precedence levels) of any precedence system,
making it difficult to gain widespread implementation of a single
precedence system.
For example, should there be support for combining different ranged
comparisons, to support notations such as
<samp>{a < b <= c}</samp>?
Should unranged comparisons (e.g., <code>=</code>) have a different
precedence than ranged comparisons (e.g., <code>>=</code>)?
Should some operators be right-associative, and if so, which ones?
(Exponentiation and assignment are often right-associative.)
Some symbols have different semantics in different contexts
(e.g., <code>=</code> may mean equal-to or assignment in different
contexts), and this complicates setting precedence levels of some operators.
Although many languages (including C and Java)
give multiplication and division the
same left-associative precedence, even that is not universal;
<a href="http://en.wikipedia.org/w/index.php?title=Order_of_operations&oldid=520621877">multiplication is considered higher precedence than division</a> in
the manuscript submission instructions for the <i>Physical Review</i> journals,
the <i>Course of Theoretical Physics</i> by Landau and Lifshitz,
and the <i>Feynman Lectures on Physics</i>.
In addition,
Wolfram Alpha considers implied (but not explicit) multiplication
higher precedence than division.