git @ Cat's Eye Technologies Carriage / 2cee992
Import text from the esowiki article, into the README. Chris Pressey 2 years ago
1 changed file(s) with 232 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
11 ========
22
33 This is the long-missing reference distribution for Carriage.
4
5 The following text was adapted from [the esowiki entry on Carriage](https://esolangs.org/wiki/Carriage),
6 which is in the public domain.
7
8 - - - -
9
10 **Carriage** is a concatenative programming language designed by Chris Pressey
11 in mid-November 2012. It is the result of trying to devise a "pure"
12 concatenative language, i.e. one where the rule "concatenation = function
13 composition" is taken to be strictly literal and universal (with no exceptions
14 such as allowing nested quoted programs.) It falls short of
15 that goal somewhat, but it has some mildly unusual properties, so it is presented
16 here as an esoteric programming language.
17
18 Note that this article describes Carriage version 0.1. It will not be version 1.0
19 until the author assures himself that there are no more instructions that are needed
20 to write simple programs, and no fatal flaws.
21
22 ### State
23
24 The state of a Carriage program is a stack of unbounded size. Each element on
25 the stack may be of one of three types:
26
27 * an unbounded integer
28 * a function which takes stacks to stacks
29 * an instruction symbol
30
31 ### Syntax
32
33 Carriage defines nine instruction symbols. Each instruction symbol has an
34 interpretation as a function which takes stacks to stacks.
35
36 Any sequence of instructions (including an entire Carriage program) has two
37 interpretations:
38
39 * the *code interpretation*, which is the composition of the functions
40 represented by each of the instruction symbols, in the manner of
41 concatenative languages. For example, if the instruction symbol `A`
42 has the interpretation f(s), and the instruction symbol `B` has the
43 interpretation g(s), then the sequence `AB` has the interpretation
44 g(f(s)). A sequence of length zero is taken to be the identity function.
45 * the *data interpretation*, where the sequence of instruction symbols
46 is taken to be a stack of instruction symbols, with the first symbol
47 in the sequence at the bottom of the stack. A sequence of length
48 zero is taken to be an empty stack.
49
50 Whitespace has no meaning; the code interpretation of whitespace is the
51 identity function, and the data interpretation does not introduce any
52 instruction symbol onto the stack. However, attempting to take the code
53 interpretation of any other symbol which is not defined by Carriage
54 will cause the program to explode.
55
56 ### Semantics
57
58 Evaluation of a Carriage program can be summed up in one sentence: The
59 function which the program represents under the code interpretation is
60 applied to the stack which the program represents under the data interpretation.
61
62 The result of executing a Carriage program is always either the stack to
63 which the initial stack was mapped by the function, or an explosion.
64
65 The instruction symbols defined by Carriage are listed below. The functions
66 to which they are mapped by the interpretation function are described in
67 operational terms for simplicity of explanation, but they are really
68 functions which take stacks to stacks.
69
70 * `1` ("one") pushes the integer 1 onto the stack.
71
72 * `~` ("pick") pops an integer n off the stack, then copies the element which is n (zero-based) positions deep in the stack, and pushes that copy onto the stack. If n is negative or greater than the size of the stack or not an integer, the program explodes. If the element to be copied is an instruction symbol, the program explodes.
73
74 * `\\` ("swap") pops an element a off the stack, then pops an element b off the stack, then pushes a back onto the stack, then pushes b back onto the stack.
75
76 * `$` ("pop") pops an element off the stack and discards it.
77
78 * `#` ("size") counts the number of elements into an integer k then pushes k onto the stack.
79
80 * `+` ("add") pops an integer a off the stack, then pops an integer b off the stack, then pushes the sum (a + b) onto the stack. If either a or b is not an integer, the program explodes.
81
82 * `-` ("sub") pops an integer a off the stack, then pops an integer b off the stack, then pushes the difference (b - a) onto the stack. If either a or b is not an integer, the program explodes.
83
84 * `@` ("slice") pops an integer k off the stack, then pops an integer p off the stack. It then copies k instruction symbols from the stack into a sequence, starting at stack position p, zero-based, measured from the bottom of the stack. It then applies the code interpretation to this sequence to obtain a function. It then pushes this function onto the stack. If k or p is not an integer, or k is less than 0, or k is greater than 0 and either p or p+(k-1) refers to some position not inside the stack proper, or k is greater than 0 and any of the elements between p and p+(k-1) inclusive are not instruction symbols, the program explodes.
85
86 * `!` ("apply") pops a function f off the stack and applies f to the stack to obtain a new stack. If f is not a function the program explodes.
87
88 If the stack is empty any time an attempt is made to pop something off of it, the program explodes.
89
90 ### Examples
91
92 #### Basic Stack Manipulation
93
94 As a simple example, the Carriage program
95
96 111-~+
97
98 will be turned into a function which we might spell out in, say, Erlang, as
99
100 fun(S) -> add(pick(sub(one(one(one(S))))))
101
102 which will be applied to a stack
103
104 (fun(S) -> add(pick(sub(one(one(one(S)))))))(["1","1","1","-","~","+"])
105
106 which could be stated more succinctly as
107
108 add(pick(sub(one(one(one(["1","1","1","-","~","+"]))))))
109
110 and whose evaluation could be depicted as
111
112 add(pick(sub(one(one(["1","1","1","-","~","+",1])))))
113 add(pick(sub(one(["1","1","1","-","~","+",1,1]))))
114 add(pick(sub(["1","1","1","-","~","+",1,1,1])))
115 add(pick(["1","1","1","-","~","+",1,0]))
116 add(["1","1","1","-","~","+",1,1])
117
118 finally evaluating to the result stack
119
120 ["1","1","1","-","~","+",2]
121
122 (Note that stacks are being depicted bottom-to-top. I realize that's not how you'd typically
123 implement them as lists in a functional language. Please just ignore that detail.)
124
125 #### Function Creation and Application
126
127 The previous example does not really demonstrate the power of the language. For that,
128 we need to show how apply, and more importantly slice, work. Take the program
129
130 11+$11+111+@!
131
132 The result stack of evaluating this program is
133
134 ["1","1","+","$","1","1","+","1","1","1","+","@","!",3]
135
136 The interpretation of the first four instruction symbols is just the
137 identity function (create 2 then pop it, leaving the stack as it was.)
138
139 The next seven instruction symbols leave [2,1,2] on the stack.
140
141 The slice instruction then pops k = 2, p = 1, and retrieves a sequence of
142 2 instruction symbols from the stack starting from position 1 (that is, the element
143 on top of the bottom element of the stack.) We can
144 see that that sequence is `1+`. It then applies the code interpretation
145 to that sequence to get a function (which pops a value off a stack and
146 pushes the successor of that value back onto the stack) and it pushes
147 this function onto the stack, which now looks like this:
148
149 [...,"!",2,<fn>]
150
151 Finally, the apply instruction pops the function, and applies it to the
152 stack: the 2 is popped, 1 is added to it, and the result, 3, is pushed
153 back on.
154
155 ##### Note on "slice"
156
157 We note that slice has the practical effect of ''delimiting'' some part
158 of the program into a "subroutine" of sorts. However, there are some
159 unusual consequences here.
160
161 One is that these "subroutines" may overlap.
162
163 Another is that these "subroutines" may be of variable size, as k need
164 not be a constant. This may be used to affect a conditional of sorts.
165 (k is allowed to be zero, in which case the slice is a zero-length
166 sequence whose interpretation is the identity function.)
167
168 Another is that, in a terminating and non-exploding program, every
169 "subroutine" must be evaluated at least once -- because the entire
170 program is turned into a single function (which is applied to the
171 initial stack) and this single function contains all of its possible
172 subroutines.
173
174 In the above example, we anticipated this, and wrote our "subroutine" so that
175 the first time it is evaluated, it has no effect. In fact, through
176 lucky coincidence, if we remove it from the program, the second and
177 third instruction symbols are still `1` and `+`, so we didn't need to
178 go to such lengths. But this is in general not the case.
179
180 Note also that the restriction on the pick instruction, that it not be
181 able to pick instruction symbols from the stack, was introduced to
182 prevent construction of new "subroutines" which did not exist in the
183 original program. (Instruction symbols can still be popped and swapped,
184 but these modifications to the "program on the stack" are quite minor.)
185
186 Note also that, despite being a concatenative language, and thus supposedly
187 mathematically pleasing, evaluating a "subfunction" with slice and apply
188 has a distinctly machine-language feel to it (similar perhaps to [Aubergine][]
189 and [Cfluviurrh][]), what with the absolute indexes into the stack and all.
190 One small saving grace is that adding whitespace to the program does *not*
191 change the indexes of the "subroutines".
192
193 #### Infinite Loop
194
195 111-@11-~!$11111++++11-~@11-~!
196
197 Explanation:
198
199 111-@
200
201 Push identity function (zero-length slice at position 1) onto the stack.
202
203 11-~!
204
205 Duplicate object on the stack and apply it. (This is our subfunction.)
206
207 $
208
209 Remove identity function from the stack.
210
211 11111++++11-~@
212
213 Push our subfunction (slice at position 5 with length 5) onto the stack.
214
215 11-~!
216
217 Duplicate object on the stack and apply it. This applies our subfunction, with our subfunction already on the stack; so the subfunction will duplicate it, then apply its copy, ad infinitum. (A cleverer implementation might be able to use this last snippet of code ''as'' the subfunction.)
218
219 ### See also
220
221 * [the esowiki entry on Carriage](https://esolangs.org/wiki/Carriage) for more
222 analysis and examples, including a Truth-machine, and open questions regarding
223 the status of this language.
224 * [Carriage.hs](https://esolangs.org/wiki/Carriage/Carriage.hs), a quick-and-dirty
225 implementation in Haskell. (which is actually the reference implementation now, okay)
226 * [Carriage.ml](https://esolangs.org/wiki/Carriage/Carriage.ml), an implementation in Ocaml.
227 * [Equipage][], the "purely concatenative" language that
228 Carriage might've been, had the author not been so concerned about quoting at the time.
229 * [Wagon][], yet another "purely concatenative" language by the same author, trying to
230 capture control flow in being "second-order concatenative", and not quite succeeding.
231
232 [Aubergine]: https://catseye.tc/node/Aubergine
233 [Cfluviurrh]: https://catseye.tc/node/Cfluviurrh
234 [Equipage]: https://catseye.tc/node/Equipage
235 [Wagon]: https://catseye.tc/node/Wagon