You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: public/index.html
+8-12Lines changed: 8 additions & 12 deletions
Original file line number
Diff line number
Diff line change
@@ -13,7 +13,7 @@
13
13
<h1id="cognate">Cognate</h1>
14
14
<h2id="readable-and-concise-concatenative-programming">Readable and concise concatenative programming</h2>
15
15
<divclass="code">
16
-
<pre>~~ Fizzbuzz in Cognate
16
+
<pre><code>~~ Fizzbuzz in Cognate
17
17
18
18
Def Multiple as (Zero? Modulo);
19
19
@@ -23,11 +23,10 @@ <h2 id="readable-and-concise-concatenative-programming">Readable and concise con
23
23
Case (Multiple of 5) is "buzz"
24
24
otherwise ();
25
25
26
-
For each in Range 1 to 100 (Print Fizzbuzz)
27
-
</pre>
26
+
For each in Range 1 to 100 (Print Fizzbuzz)</code></pre>
28
27
</div><p>Cognate is a project aiming to create a human readable programming language with as little syntax as possible. Where natural language programming usually uses many complex syntax rules, instead Cognate takes them away. What it adds is simple, a way to embed comments into statements.</p>
29
28
<divclass="code">
30
-
<pre>~~ Towers of Hanoi in Cognate
29
+
<pre><code>~~ Towers of Hanoi in Cognate
31
30
32
31
Def Move discs as (
33
32
@@ -43,19 +42,17 @@ <h2 id="readable-and-concise-concatenative-programming">Readable and concise con
43
42
)
44
43
);
45
44
46
-
Move 5 discs from "a" via "b" to "c"
47
-
</pre>
45
+
Move 5 discs from "a" via "b" to "c"</code></pre>
48
46
</div><p>As you can see, Cognate ignores words starting with lowercase letters, allowing them to be used to describe functionality and enhance readability. This makes Cognate codebases intuitive and maintainable.</p>
49
47
<divclass="code">
50
-
<pre>~~ Square numbers in Cognate
48
+
<pre><code>~~ Square numbers in Cognate
51
49
52
50
Def Square as (* Twin);
53
51
Map (Square) over Range 1 to 10;
54
-
Print
55
-
</pre>
52
+
Print</code></pre>
56
53
</div><p>Cognate is a stack-oriented programming language similar to Forth or Factor, except statements are evaluated right to left. This gives the expressiveness of concatenative programming as well as the readability of prefix notation. Statements can be delimited at arbitrary points, allowing them to read as sentences would in English.</p>
57
54
<divclass="code">
58
-
<pre>~~ Prime numbers in Cognate
55
+
<pre><code>~~ Prime numbers in Cognate
59
56
60
57
Def Factor (Zero? Modulo Swap);
61
58
@@ -72,8 +69,7 @@ <h2 id="readable-and-concise-concatenative-programming">Readable and concise con
72
69
)
73
70
);
74
71
75
-
Print Primes up to 1000;
76
-
</pre>
72
+
Print Primes up to 1000;</code></pre>
77
73
</div><p>Cognate borrows from other concatenative languages, but also adds unique features of its own.</p>
Copy file name to clipboardExpand all lines: public/learn/index.html
+54-87Lines changed: 54 additions & 87 deletions
Original file line number
Diff line number
Diff line change
@@ -15,29 +15,24 @@ <h2 id="install">Install</h2>
15
15
<p>First install <code>CognaC</code> the Cognate Compiler from here using the provided instructions. Currently <code>CognaC</code> will run on recent Linux or Mac systems. Windows users can install it onto the Windows Subsystem for Linux - native Windows support is planned.</p>
16
16
<p>Invoking <code>CognaC</code> is simple. If you have a file named <code>foo.cog</code> containing a Cognate program, it can be compiled into an executable named <code>foo</code> with the following command.</p>
17
17
<divclass="code">
18
-
<pre>cognac foo.cog
19
-
</pre>
18
+
<pre><code>cognac foo.cog</code></pre>
20
19
</div><p>To compile a debug executable, which will run slower but give a nice backtrace if there’s an error, you can use the <code>-debug</code> flag.</p>
21
20
<p>Alternatively, you can use the interactive web playground <ahref="https://cognate-playground.hedy.dev/">here</a> which runs Cognate programs client-side in the browser. It also has intelligent syntax highlighting, code folding, and error reporting in the editor</p>
22
21
<h2id="first-programs">First Programs</h2>
23
22
<divclass="code">
24
-
<pre>Print "Hello world!";
25
-
</pre>
23
+
<pre><code>Print "Hello world!";</code></pre>
26
24
</div><p>Fairly simple right? This example calls the <code>Print</code> function with one parameter - the string <code>"Hello world!"</code>. Now let’s do another simple example, adding two numbers.</p>
27
25
<divclass="code">
28
-
<pre>Print + 2 3;
29
-
</pre>
26
+
<pre><code>Print + 2 3;</code></pre>
30
27
</div><p>Wait what? That isn’t how maths works!</p>
31
28
<p>Cognate doesn’t care how maths works. Where in most programming languages, <code>+</code> would be an operator and would be used in the infix position, in Cognate <code>+</code> is a function. Like <code>Print</code>, the <code>+</code> function is called by being written before its arguments like shown above.</p>
32
29
<divclass="code">
33
-
<pre>Print - 10 36; ~~ Subtracts 10 from 36
34
-
</pre>
30
+
<pre><code>Print - 10 36; ~~ Subtracts 10 from 36</code></pre>
35
31
</div><p>Another thing to note is that the order of parameters for <code>-</code> and <code>/</code> are backwards. The reason for this will become clear later. Also note that line comments are started with <code>~~</code>.</p>
36
32
<h2id="the-stack">The Stack</h2>
37
33
<p>Let’s have a more complex example, this subtracts 12 from 15 and then multiplies the result by 2.</p>
38
34
<divclass="code">
39
-
<pre>Print * 2 - 12 15;
40
-
</pre>
35
+
<pre><code>Print * 2 - 12 15;</code></pre>
41
36
</div><p>By now you may have realised that Cognate is evaluating our programs backwards - right to left. The subtraction is being performed before the multiplication above. This is being done using a stack, as explained here.</p>
<p>Cognate comes with functions to manipulate the stack. The simplest of these is <code>Twin</code>, which takes the top element from the stack, and puts it back on again - twice. The below snippet uses <code>Twin</code> to square a number by multiplying it by itself.</p>
51
46
<divclass="code">
52
-
<pre>Print * Twin 8;
53
-
</pre>
47
+
<pre><code>Print * Twin 8;</code></pre>
54
48
</div><p>Now we don’t want to write this every time we square a number right? So let’s create a <code>Square</code> function to do this for us.</p>
55
49
<h2id="first-functions">First Functions</h2>
56
50
<p>Functions in Cognate are defined using <code>Def</code> and the name of the function. The function body is put in brackets after this.</p>
57
51
<divclass="code">
58
-
<pre>Def Square (* Twin);
59
-
Print Square 8;
60
-
</pre>
52
+
<pre><code>Def Square (* Twin);
53
+
Print Square 8;</code></pre>
61
54
</div><p>This is great, but it certainly could flow better. Cognate ignores words starting with lowercase letters, allowing them to be used as comments. This lets us write:</p>
62
55
<divclass="code">
63
-
<pre>Print the Square of 8;
64
-
</pre>
56
+
<pre><code>Print the Square of 8;</code></pre>
65
57
</div><p>In this example the readability isn’t really improved much, but in more complex programs this informal syntax can be invaluable.</p>
66
58
<p>By now you’ve probably noticed the semicolons. These delimit statements so that Cognate knows what order to evaluate functions in (remember that these are executed backwards). Definitions should also be terminated with semicolons. The stack persists between statements, letting us do things like this.</p>
67
59
<divclass="code">
68
-
<pre>8 ; Square ; Print ;
69
-
</pre>
60
+
<pre><code>8 ; Square ; Print ;</code></pre>
70
61
</div><p>or this</p>
71
62
<divclass="code">
72
-
<pre>Square 8 ; Print ;
73
-
</pre>
63
+
<pre><code>Square 8 ; Print ;</code></pre>
74
64
</div><p>or this</p>
75
65
<divclass="code">
76
-
<pre>8 ; Print the Square ;
77
-
</pre>
66
+
<pre><code>8 ; Print the Square ;</code></pre>
78
67
</div><p>This flexible syntax allows Cognate programs to flow as if written in sentences. It also means that much of the time variables are not even needed. Of course, Cognate <em>does</em> have variables.</p>
79
68
<h2id="variables">Variables</h2>
80
69
<p>Variables are defined in a fairly similar manner to functions using <code>Let</code> and their name. This takes a value from the stack, binding it to this name. Variables are referenced with the same syntax in which functions are called.</p>
81
70
<divclass="code">
82
-
<pre>Let X be 4;
83
-
Print X;
84
-
</pre>
71
+
<pre><code>Let X be 4;
72
+
Print X;</code></pre>
85
73
</div><p>We can use variables to define functions that take named parameters - here’s an alternate version of the <code>Square</code> function.</p>
86
74
<divclass="code">
87
-
<pre>Def Square as (
75
+
<pre><code>Def Square as (
88
76
Let X;
89
77
* X X
90
-
);
91
-
</pre>
78
+
);</code></pre>
92
79
</div><p>Notice that the last statement before a closing bracket does not need to be terminated with a semicolon. Also there is no return statement, since values are implicitly returned on the stack. This means we can actually define functions that return multiple values, such as the <code>Twin</code> function we saw earlier.</p>
93
80
<divclass="code">
94
-
<pre>Def Twin as (
81
+
<pre><code>Def Twin as (
95
82
Let X;
96
83
X X
97
-
);
98
-
</pre>
84
+
);</code></pre>
99
85
</div><h2id="control-flow">Control Flow</h2>
100
86
<p>Like most programming languages, Cognate has if statements and loops and all that jazz. The simplest form of control flow is <code>When</code>, which simply executes a block of code if given <code>True</code> or not if <code>False</code>.</p>
101
87
<divclass="code">
102
-
<pre>When == 1 1 (
88
+
<pre><code>When == 1 1 (
103
89
Print "Who'd have guessed?"
104
-
);
105
-
</pre>
90
+
);</code></pre>
106
91
</div><p>There is also <code>Unless</code> that evaluates the block if given <code>False</code>. <code>While</code> takes a condition in brackets and evaluates the block of code until the condition is <code>False</code>. <code>Until</code>, you guessed it, is the opposite of <code>While</code> and runs until the condition is <code>True</code>.</p>
107
92
<divclass="code">
108
-
<pre>While (True) (
93
+
<pre><code>While (True) (
109
94
Print "This may well print forever"
110
-
);
111
-
</pre>
95
+
);</code></pre>
112
96
</div><p>What’s with the second set of brackets? <code>When</code> doesn’t have them, so why should <code>While</code>? This is because brackets denote blocks! These prevent code being instantly evaluated and instead push a reference onto the stack. Blocks also control variable scopes. We can evaluate a block using the <code>Do</code> function - which is how our control flow functions are implemented.</p>
113
97
<divclass="code">
114
-
<pre>Do (
98
+
<pre><code>Do (
115
99
Print "Hello from inside a block!"
116
-
);
117
-
</pre>
100
+
);</code></pre>
118
101
</div><p>This explains the syntax for functions: <code>Def</code> simply binds a block to a name, much like <code>Let</code>. Blocks can be passed around the program like any other value - even if they reference variables that go out of scope.</p>
119
102
<p>Now that this (hopefully) makes some sense, we can finally introduce the <code>If</code> statement! <code>If</code> is a function that takes three parameters. The first is a boolean, if this is <code>True</code> then the second argument is returned. If not, the third argument is returned. We can chain <code>If</code>s together to have more complex control flow.</p>
120
103
<divclass="code">
121
-
<pre>Print
104
+
<pre><code>Print
122
105
If == X 1 then "foo"
123
106
If == X 2 then "bar"
124
-
else "baz";
125
-
</pre>
107
+
else "baz";</code></pre>
126
108
</div><p>We can combine this with <code>Do</code> to have conditional code execution.</p>
127
109
<divclass="code">
128
-
<pre>Do
110
+
<pre><code>Do
129
111
If == X 1 then ( Print "foo" )
130
112
If == X 2 then ( Print "bar" )
131
-
else ( Print "baz" );
132
-
</pre>
113
+
else ( Print "baz" );</code></pre>
133
114
</div><p>Now, lets use our knowledge of blocks to define our own control flow function <code>Thrice</code>, which should evaluate a block three times in a row. This demonstrates a different use of <code>Def</code> in which we bind a block from the stack.</p>
134
115
<divclass="code">
135
-
<pre>Def Thrice as (
116
+
<pre><code>Def Thrice as (
136
117
Def F;
137
118
F F F
138
119
);
139
120
140
121
Thrice (
141
122
Print "hip hip hooray!"
142
-
);
143
-
</pre>
123
+
);</code></pre>
144
124
</div><p>A more general version of this function, <code>Times</code> can be defined using recursion.</p>
145
125
<divclass="code">
146
-
<pre>Def Times (
126
+
<pre><code>Def Times (
147
127
Let N number of repetitions;
148
128
Def F function to repeat;
149
129
Unless Zero? N ( F ; Times - 1 N (F) );
150
130
);
151
131
152
132
Times 5 (
153
133
Print "wow!";
154
-
);
155
-
</pre>
134
+
);</code></pre>
156
135
</div><p>Now you may see a small problem with this. If the user calls <code>Times</code> with a non-integer parameter it will loop forever - that won’t do at all! We use the <code>Integer!</code> function to throw a type error if a decimal is given.</p>
157
136
<divclass="code">
158
-
<pre>Def Times (
137
+
<pre><code>Def Times (
159
138
Let N is Integer! number of repetitions;
160
139
Def F function to repeat;
161
140
Unless Zero? N ( F ; Times - 1 N (F) );
162
-
);
163
-
</pre>
141
+
);</code></pre>
164
142
</div><p>We could also use the <code>Block!</code> function for <code>F</code> but we’ll already get a type error when we use <code>Def</code> to bind anything that isn’t a block, so there is no point.</p>
165
143
<p>The <code>Times</code> function is also our first loop. We don’t need to define it every time though as it’s also in the standard library. Another loop is <code>While</code>.</p>
166
144
<divclass="code">
167
-
<pre>While (!= "done" Twin Input) (
145
+
<pre><code>While (!= "done" Twin Input) (
168
146
Print
169
147
);
170
-
Drop;
171
-
</pre>
148
+
Drop;</code></pre>
172
149
</div><p><code>While</code> takes two block parameters. The first one is the condition and is evaluated immediately, returning a boolean. If this is <code>True</code> then the second block (the loop body) is evaluated and then the loop repeats, if not the loop finishes. The example above shows the use of a <code>While</code> loop. The program simply echoes the user’s inputs back to them until they write <code>"done"</code>.</p>
173
150
<p>This loop is most useful in imperative code where intermediary values are passed on the stack between iterations. It is less useful for iterating over data structures such as lists. Lists?</p>
174
151
<h2id="lists">Lists</h2>
175
152
<p>In Cognate, lists are generated using - you guessed it - a function. The <code>List</code> function takes a block as a parameter. It evaluates this block <em>in a new stack</em> and then returns that stack as a list.</p>
176
153
<divclass="code">
177
-
<pre>Print List (1 2 3 4 5);
178
-
</pre>
154
+
<pre><code>Print List (1 2 3 4 5);</code></pre>
179
155
</div><p>This allows Cognate’s list creation to be much more flexible than other languages - for example what if we wanted a list of 100 ones?</p>
180
156
<divclass="code">
181
-
<pre>Print List ( Times 100 (1) );
182
-
</pre>
157
+
<pre><code>Print List ( Times 100 (1) );</code></pre>
183
158
</div><p>The three most fundamental list functions are <code>Push</code>, <code>First</code>, and <code>Rest</code>.</p>
184
159
<p>The <code>Push</code> function takes a value and a list as parameters, and returns the list with the value <em>pushed</em> to it’s first element. <code>First</code> simply returns the first element of a list. <code>Rest</code> returns a list without its first element.</p>
185
160
<divclass="code">
186
-
<pre>Let L be Push "foo" to List ( "bar" "baz" );
161
+
<pre><code>Let L be Push "foo" to List ( "bar" "baz" );
187
162
Print First element of L;
188
-
Print Rest of L;
189
-
</pre>
163
+
Print Rest of L;</code></pre>
190
164
</div><p><code>Range</code> creates a list of numbers from a starting (inclusive) and an ending (exclusive) number. <code>For</code> is a higher order function that applied an operation to each element of a list - it is the loop for iterating over lists.</p>
191
165
<divclass="code">
192
-
<pre>Def Square as (* Twin);
193
-
For each in Range 1 to 20 (Print the Square);
194
-
</pre>
166
+
<pre><code>Def Square as (* Twin);
167
+
For each in Range 1 to 20 (Print the Square);</code></pre>
195
168
</div><p><code>Map</code> is like <code>For</code> but the result of the computation is stored in a new list.</p>
196
169
<divclass="code">
197
-
<pre>Let Evens be Map (* 2) over Range 1 to 50;
198
-
Print Evens;
199
-
</pre>
170
+
<pre><code>Let Evens be Map (* 2) over Range 1 to 50;
171
+
Print Evens;</code></pre>
200
172
</div><p><code>Filter</code> applies a function to each element of a list also. This function should return a boolean - if this is <code>False</code> then the function is removed from the returned list.</p>
201
173
<divclass="code">
202
-
<pre>Let Even? be (Zero? Modulo 2);
174
+
<pre><code>Let Even? be (Zero? Modulo 2);
203
175
Let Evens be Filter (Even?) over Range 1 to 100;
204
-
Print Evens;
205
-
</pre>
176
+
Print Evens;</code></pre>
206
177
</div><p>The functional programmers reading this are likely expecting a Fold or Reduce function next - which applies an operation to a list with an accumulator. However Cognate needs no fold function, as <code>For</code> can store intermediary values on the stack, acting like a fold.</p>
207
178
<divclass="code">
208
-
<pre>Def Factorial as (
179
+
<pre><code>Def Factorial as (
209
180
Let N be Integer!;
210
181
For each in Range 1 to N (*) from 1;
211
182
);
212
183
213
-
Print Factorial 10;
214
-
</pre>
184
+
Print Factorial 10;</code></pre>
215
185
</div><h2id="boxes">Boxes</h2>
216
186
<p>While storing state between loop iterations is very useful, in some cases you just need mutable variables. Cognate’s boxes are references used to generalise the concept of mutation.</p>
217
187
<p>The <code>Box</code> function takes a value and places it in a box. <code>Unbox</code> returns the item stored in a box. <code>Set</code> takes a box and a value as parameters and mutates the box to hold the value, updating all references to it.</p>
218
188
<divclass="code">
219
-
<pre>Let X be Box 1;
189
+
<pre><code>Let X be Box 1;
220
190
Print Unbox X; ~~ prints 1
221
191
222
192
Set X to 2;
223
-
Print Unbox X; ~~ prints 2
224
-
</pre>
193
+
Print Unbox X; ~~ prints 2</code></pre>
225
194
</div><p>Boxes aren’t limited to mutating variables, they can be used for any value.</p>
226
195
<divclass="code">
227
-
<pre>Let L be Map (Box) over Range 1 to 10;
196
+
<pre><code>Let L be Map (Box) over Range 1 to 10;
228
197
Print L;
229
198
230
199
For each in L (
231
200
Let X;
232
201
Set X to * 2 Unbox X; ~~ double the element in place
233
202
);
234
-
Print L;
235
-
</pre>
203
+
Print L;</code></pre>
236
204
</div><p>While boxes may not seem as ergonomic as mutation in other languages, they are both more flexible than mutable variables and more predictable than implicit references. We can also easily extend mutation, like this:</p>
0 commit comments