176
\$\begingroup\$

In this challenge, users will take turns completeing three fairly simple coding tasks in programming languages that are allowed to be progressively older.

The first answer must use a programming language that was made in the year 2015. Once there is at least one answer from a 2015 language, answers may use programming languages that were made in 2014. Similarly, answers that use languages from 2013 are not allowed until there is at least one 2014 answer.

In general, the use of a programming language from the year Y is not allowed until an answer using a language from the year Y+1 has been submitted. The only exception is Y = 2015.

Finding Your Language's Year

To answer this question, you must know the year your programming language was "made in". This is, of course, a subjective term; some languages were developed over the course of multiple years, and many languages are still being upgraded every year. Let the year a language was "made in" be the first year an implementation for that language appeared in the general public.

For example, Python was "made in" 1991, though its development had been in progress since 1989, and version 1.0 wasn't released until 1994.

If this year is still subjective, just use your common sense to choose the most appropriate year. Don't get bogged down in slight disagreements about year choices. Please provide a link to a source that says when your language was made.

Different versions or standards of a programming language (e.g. Python 1, 2, 3) are counted as the same language with the same initial year.

So, unless your language's year is 2015, you can only submit your answer once an answer has been submitted whose language's year is the year just before yours.

If a valid answer with the same year as yours already exists, then you may answer. It doesn't matter if your language was developed earlier or later in the year.

Tasks

You must complete Tasks 1 through 3. Task 0 is optional.

These tasks were more or less chosen to correspond to three important aspects of programming: providing output (Task 1), looping (Task 2), and recursion (Task 3).

Task 0 - Language History (optional)

Write at least a paragraph explaining the history of your chosen programming language: who developed it, why, how, etc. This is especially encouraged if you personally were around when the language came into being, and maybe even played a part in its development. Feel free to relate personal anecdotes about the effect the language had on you or your job, or anything like that.

If you're too young to know much about the history of your language without a lot of research, consider leaving a note to older users that says they can edit your post and add in some first-hand history.

Task 1 - "Hello, World!" Variant

Write a program that prints

[language name] was made in [year made]!

to your language's standard output area (stdout for most recent languages).

For example, if the language was Python, the output would be:

Python was made in 1991!

Task 2 - ASCII Art N

Write a program that lets the user enter in an odd positive integer (you may assume the input is always valid), and prints out an ASCII art letter N made using the character N.

If the input is 1, the output is:

N

If the input is 3, the output is:

N N
NNN
N N

If the input is 5, the output is:

N   N
NN  N
N N N
N  NN
N   N

If the input is 7, the output is:

N     N
NN    N
N N   N
N  N  N
N   N N
N    NN
N     N

The pattern continues on like this. The output may contain trailing spaces.

Task 3 - GCD

Write a program that lets the user enter in two positive integers (you may assume the input is always valid), and prints their greatest common divisor. This is defined as the largest positive integer that divides both numbers without leaving a remainder. It can be readily calculated using the Euclidean algorithm.

Examples:

8, 124
12, 84
3, 303
5689, 21
234, 8766

You may use a built in function but try finding out if it was there in the first version of your language. If not, try not using it.

Rules

  • You may answer multiple times, but each new answer must use a language made at least 5 years before the language in your last answer. So if you answered with a 2015 language, you couldn't answer again until 2010 languages are allowed. If you start with a 2010 answer, you can't make a 2015 answer your second answer because 2015 is not before 2010.
  • If possible, write your code so that it would have worked in the very first version of your language (or as old a version as possible). (This is not a requirement because finding old compilers/interpreters for some languages may be difficult.)
  • Refrain from posting a language that has already been posted unless the posted answer has significant errors or you have a very different way of completing the tasks.
  • Golfing your code is fine but not required.
  • A trailing newline in the output of any program is fine.
  • For tasks 2 and 3, all input values below some reasonable maximum like 216 should work (256 at the very least).
  • Your language must have existed before this question was posted.
  • Very old programming languages may have different forms of input and output than what we think of today. This is fine. Complete the tasks to the best of your ability in the context of your language.

Scoring

Your submission's score is:

upvotes - downvotes + (2015 - languageYear) / 2 

Thus, 0.5 is added to the vote count for every year before 2015, giving the advantage to older languages. The submission with the highest score wins.

Answer List

The Stack Snippet below lists all the valid answers according to their language year.

You must start your post with this Markdown line to ensure it is listed correctly:

#[year] - [language name]

For example:

#1991 - Python

The language name may be in a link (it will be the same link in the answer list):

#1991 - [Python](https://www.python.org/)

Answers that don't follow this format, or have a year that is not allowed yet, or come from a user that already answered in the last 5 years are marked as invalid.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><script>$(function(){function e(e,r){var a="https://api.stackexchange.com/2.2/questions/48476/answers?page="+e.toString()+"&pagesize=100&order=asc&sort=creation&site=codegolf&filter=!YOKGPOBC5Yad160RQxGLP0r4rL";$.get(a,r)}function r(e){if(e.items.forEach(function(e){var r=e.link,a=e.owner.display_name,i=e.body.match(/<h1\b[^>]*>(\d{4}) - (.*?)<\/h1>/);if(i&&i.length>=3)var h=parseInt(i[1]),u=i[2];h&&u&&n>=h&&h>=t&&(!d.hasOwnProperty(e.owner.user_id)||d[e.owner.user_id]-h>=p)?(d[e.owner.user_id]=h,h==t&&--t,o.hasOwnProperty(h)||(o[h]=[]),o[h].push({language:u,user:a,link:r,score:e.score+(n-h)/2})):s.push(' <a href="'+r+'">'+a+"</a>")}),e.has_more)runQuery(++a,r);else{for(var i=n,h=[];o.hasOwnProperty(i);){for(var u=$("<tr>").append($("<td>").text(i.toString())),l=$("<td>"),c=$("<td>"),g=$("<td>"),f=0;f<o[i].length;f++){var v=o[i][f];l.append(v.language),c.append($("<a>").html(v.user).attr("href",v.link)),g.append(v.score),f+1<o[i].length&&(l.append("<br><br>"),c.append("<br><br>"),g.append("<br><br>"))}u.append(l).append(c).append(g),h.push(u),--i}$("#answers").find("tbody").append(h),s.length>0?$("#invalid").append(s):$("#invalid").remove()}}var a=1,n=2015,t=n-1,p=5,o={},s=[],d={};e(1,r)})</script><style>html *{font-family: Helvetica, Arial, sans-serif;}table{border: 4px solid #a4a; border-collapse: collapse;}th{background-color: #a4a; color: white; padding: 8px;}td{border: 1px solid #a4a; padding: 8px;}div{font-size: 75%;}</style><table id='answers'> <tr> <th>Year</th> <th>Language</th> <th>User (answer link)</th> <th>Score</th> </tr></table><div id='invalid'><br>Invalid Answers:</div>

\$\endgroup\$
16
  • 2
    \$\begingroup\$ This should help. \$\endgroup\$
    – swish
    Apr 6, 2015 at 9:10
  • 27
    \$\begingroup\$ Wikipedia has a list for everything: this one for non-esoteric languages by year. \$\endgroup\$
    – Sanchises
    Apr 6, 2015 at 12:30
  • 2
    \$\begingroup\$ Should Task 3 actually use recursion or is it enough that it produces the correct result? If I need to write my own GCD function I usually just use a loop but I wrote a recursive one specially for this challenge. There are many submitted answers that just use a loop. \$\endgroup\$
    – CJ Dennis
    May 3, 2015 at 2:51
  • 5
    \$\begingroup\$ I feel like making a second account just to get us past 1971. \$\endgroup\$
    – marinus
    May 5, 2015 at 10:49
  • 6
    \$\begingroup\$ If we can get it back to 1952, I have someone spinning up a historic machine that could do 1951 (Pegasus) solutions and test them! \$\endgroup\$ May 19, 2015 at 18:19

101 Answers 101

182
\$\begingroup\$

2013 - Dogescript

Dogescript is a language created in 2013 by Zach Bruggeman. It is nothing more than a syntax-replacement for Javascript to make it read like the internal monologues of memetic Shiba Inus.

Hello doge

console dose loge with "Dogescript was made in 2013!"

ASCII Art

such N much N
          much i as 0 next i smaller N next i more 1
              very doge is ("N" + " ".repeat(N-2) + "N").split('')
              s[i] is "N";
              console dose loge with doge.join('')
                              wow
                                      wow

GCD

such gcd_doge much doge, dooge
    rly dooge
              gcd_doge(dooge, doge % dooge)
  but
    rly doge smaller 0
           -doge
    but
          doge
  wow
        wow
\$\endgroup\$
5
  • 124
    \$\begingroup\$ Wow, such +1. Very answer. Much quality. \$\endgroup\$
    – Alex A.
    Apr 6, 2015 at 20:08
  • 30
    \$\begingroup\$ I joined codegolf just to upvote this answer! \$\endgroup\$ Apr 8, 2015 at 2:36
  • 23
    \$\begingroup\$ I can't even read the GCD one with a straight face \$\endgroup\$
    – Cole Tobin
    Apr 9, 2015 at 7:18
  • 18
    \$\begingroup\$ I can't not read gcd_doge as good_dog. Help \$\endgroup\$
    – Yann
    Apr 9, 2015 at 12:19
  • \$\begingroup\$ Fantastic. However, according to LANGUAGE.md, double quotes are not supported. Would love an explanation of the s[i] bit too! \$\endgroup\$
    – Docteur
    May 6, 2015 at 6:17
67
\$\begingroup\$

2015 - Retina

Retina is a regex-based programming language, which I wrote to be able to compete in PPCG challenges with regex-only answers, without having the unnecessary overhead of calling the regex in some host language. Retina is Turing-complete. To prove it I've implemented a 2-tag system solver as well as Rule 110. It is written in C#, hence it supports both the .NET flavour (by default) and the ECMAScript flavour (via a flag).

Retina can operate in multiple modes, but the most relevant one for computations (and the Turing-complete one) is Replace mode. In Replace mode you give Retina an even number of source files. These are then paired, the first of each pair being a regex, and the second a replacement. These are then executed in order, manipulating the input step by step. The regex can also be preceded by a configuration (delimited with `). The most important option (which makes Retina Turing-complete) is +, which makes Retina apply the replacement in a loop until the result stops changing. In the following examples, I'm also using ;, which suppresses output on intermediate stages.

In each of the following submissions, each line goes in a separate source file. (Alternatively, you can use the new -s option and put all lines into a single file.) Empty files/lines are represented as <empty>. Files/lines containing a single space are represented as <space>.

The explanations are quite long, so I've moved them to the end of the post.

The Programs

"Hello, World!" Variant

<empty>
Retina was made in 2015!

ASCII Art N

This assumes that STDIN is terminated with a newline.

;`^
#
;+`(\d*)#(?:(((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|0)
$1$1$1$1$1$1$1$1$1$1$2$3$4$5$6$7$8$9$10#
;`#
<empty>
;`\d
N
;`.(?<=(?=(.*\n)).*)|\n
$1
;`N(?=N\n.*\n.*\n`$)
<space>
;+`N(?=.?(.)+\n.* (?<-1>.)+(?(1)!)\n)
<space>
;`(?<=^.*\n.*\nN)N
S
;+`(?<=\n(?(1)!)(?<-1>.)+S.*\n(.)+N?)N
S
S
<space>

GCD

This requires that STDIN is not terminated with a newline.

;`\b(?=\d)
#
;+`(\d*)#(?:(((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|0)
$1$1$1$1$1$1$1$1$1$1$2$3$4$5$6$7$8$9$10#
;`#
<empty>
;`\d
1
;`^(.+)\1* \1+$
$1
;`$
#:0123456789
;+`^(?=1)(1*)\1{9}(#(?=.*(0))|1#(?=.*(?<3>1))|11#(?=.*(?<3>2))|111#(?=.*(?<3>3))|1111#(?=.*(?<3>4))|11111#(?=.*(?<3>5))|111111#(?=.*(?<3>6))|1111111#(?=.*(?<3>7))|11111111#(?=.*(?<3>8))|111111111#(?=.*(?<3>9)))
$1#$3
#|:.*
<empty>

Explanations

"Hello, World!" Variant

This is fairly trivial. It takes no input (i.e. an empty string), matches nothing and replaces it with Retina was made in 2015!. One can also make it work for arbitrary input, by replacing the pattern with [\s\S]* for instance. That would slurp STDIN and replace all of it with the output.

ASCII Art N

This has quite a lot of stages. The idea is to convert the input to unary, create an N x N block of Ns and then "carve out" two triangles. Let's go through the individual stages. Remember that ; merely suppresses intermediate outputs, but + causes the replacement to be applied in a loop.

;`^
#

Simple: prepend a # to the input. This will be used as a marker in the conversion to unary.

;+`(\d*)#(?:(((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|0)
$1$1$1$1$1$1$1$1$1$1$2$3$4$5$6$7$8$9$10#

This converts one digit to unary. It takes the digits already converted (\d*) and repeats them 10 times. And then it takes the next digit and appends the appropriate number of digits. The actual value of the digits is irrelevant at this stage. When the # reaches the end of the number, the regex no longer matches, and the conversion is done. As an example, the number 127 will be processed as

#127
1#27
111111111122#7
1111111111221111111111221111111111221111111111221111111111221111111111221111111111221111111111221111111111221111111111227777777#

where the last line contains exactly 127 digit characters.

;`#
<empty>
;`\d
N

Two simple stages which get rid of that # and then convert all the digits to N. In the following I'll use input 7 as an example. So now we've got

NNNNNNN

The next stage

;`.(?<=(?=(.*\n)).*)|\n
$1

replaces each N with the entire string (remember that it contains a trailing newline), and also removes the trailing newline itself. Hence, this turns the single row into a square grid:

NNNNNNN
NNNNNNN   
NNNNNNN
NNNNNNN
NNNNNNN
NNNNNNN
NNNNNNN

Now the upper triangle. First, we start things off by turning the N in the lower right corner into a space:

;`N(?=N\n.*\n.*\n`$)
<space>

The lookahead ensures that we're modifying the correct N. This gives

NNNNNNN
NNNNNNN   
NNNNNNN
NNNNNNN
NNNNN N
NNNNNNN
NNNNNNN

And now

;+`N(?=.?(.)+\n.* (?<-1>.)+(?(1)!)\n)
<space>

is a regex which matches an N which is above or at the top left corner of a space character, and replaces it with a space. Because the replacement is repeated, this is essentially a flood-fill, which turns the 3rd octant from the initial space into more spaces:

N     N
NN    N   
NNN   N
NNNN  N
NNNNN N
NNNNNNN
NNNNNNN

And finally, we repeat the same thing with the bottom triangle, but we use a different character, so the already existing spaces don't cause a wrong flood fill:

;`(?<=^.*\n.*\nN)N
S

sets the seed:

N     N
NN    N   
NSN   N
NNNN  N
NNNNN N
NNNNNNN
NNNNNNN

Then

;+`(?<=\n(?(1)!)(?<-1>.)+S.*\n(.)+N?)N
S

does the flood-fill.

N     N
NN    N   
NSN   N
NSSN  N
NSSSN N
NSSSSNN
NSSSSSN

And finally

S
<space>

Turns those S into spaces and we're done:

N     N
NN    N   
N N   N
N  N  N
N   N N
N    NN
N     N

GCD

GCD in unary is actually very trivial with regex. Most of this consists of the decimal to unary and unary to decimal conversion. This could be done more compactly, but this isn't a code golf, so...

;`\b(?=\d)
#
;+`(\d*)#(?:(((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|0)
$1$1$1$1$1$1$1$1$1$1$2$3$4$5$6$7$8$9$10#
;`#
<empty>
;`\d
1

These stages are essentially the same as above, except that both input numbers are converted, and the result uses 1s instead of Ns (not that it matters). So if the input was 18 24, then this would produce

111111111111111111 111111111111111111111111

Now

;`^(.+)\1* \1+$
$1

is the entire GCD computation. We match a common divisor by capturing a number of 1s, and then using backreferences to ensure that both numbers can be written by repeating that string (and nothing else). Due to how backtracking works in the regex engine (i.e. that .+ is greedy), this will always yield the greatest common divisor automatically. Since the match covers the entire string, we simply write back the first capturing group to get our GCD.

Finally, the unary to decimal conversion...

;`$
#:0123456789

Append a marker #, a delimiter : and all digits to the string. This is necessary, because you can't produce new characters conditionally in a regex replacement. If you want conditional replacement, you need to pull the characters from the string itself, so we put them there.

;+`^(?=1)(1*)\1{9}(#(?=.*(0))|1#(?=.*(?<3>1))|11#(?=.*(?<3>2))|111#(?=.*(?<3>3))|1111#(?=.*(?<3>4))|11111#(?=.*(?<3>5))|111111#(?=.*(?<3>6))|1111111#(?=.*(?<3>7))|11111111#(?=.*(?<3>8))|111111111#(?=.*(?<3>9)))
$1#$3

This is the inverse of the unary expansion earlier. We find the largest multiple of 10 that fits into the current string. Then we choose the next digit based on the remainder, and divide the multiple by 10, while moving the marker through the digits.

#|:.*
<empty>

And lastly just a cleanup step to get rid of the marker, delimiter and the helper digits.

\$\endgroup\$
6
  • \$\begingroup\$ I think you should add instruction to convert numeric input to unary string, and instruction to convert unary string back to numeric input. The conversion with pure regex is cool but far too clunky. \$\endgroup\$ Apr 6, 2015 at 10:10
  • 8
    \$\begingroup\$ +1 I was pretty sure 2015 submission would be a language for CodeGolf use. \$\endgroup\$
    – Zero Fiber
    Apr 6, 2015 at 10:31
  • \$\begingroup\$ @n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ I was considering that earlier. I think for most code golfs, I'd probably just take Unary input (unless the challenge explicitly specifies "decimal" or something...). I thought about doing the same for this, but this is not a code golf, and I wanted to show that I can handle decimal input and output as well. \$\endgroup\$ Apr 6, 2015 at 18:03
  • 6
    \$\begingroup\$ Excellent work. Retina is really cool. And as an aside, it's also really cool seeing the diamond next to your name! :) \$\endgroup\$
    – Alex A.
    Apr 6, 2015 at 20:08
  • \$\begingroup\$ Funny that although old languages are favored in this competition, this most youngest one is still winning =) \$\endgroup\$
    – Claudiu
    Apr 29, 2015 at 3:55
60
\$\begingroup\$

2013 - Snap!

Snap! is a language based on Scratch, made at Berkeley University. It is an upgrade to Scratch featuring first-class data and custom blocks (functions). Like Scratch, it is not text based, but rather done by visual "blocks" that snap together.

Snap!, written in JavaScript, is the successor to BYOB, which was written in Squeak Smalltalk. Snap! was beta released for public consumption in March 2013.

Snap! is actually not an esoteric language. It is used as the programming language for the Beauty and Joy of Computing (BJC) AP CS course at Berkeley and others.

I helped out with testing and stuff.

"Hello World" variant

ASCII Art "N"

enter image description here

This uses the stdlib for some of the blocks.

Pretty basic looping here. Takes an input. Then we just add it all together and say it (result for n=5):

enter image description here

I took the liberty here to just use 2 spaces instead of 1, because Snap! doesn't say stuff in monospace.

GCD

The Euclidean algorithm isn't very fast, but it works, and is pretty simple. (Sorry, i made a typo in the block name. Now i closed the tab without saving. It'll just have to stay.)

enter image description here

This function definition will then produce this block:

enter image description here

\$\endgroup\$
3
  • 3
    \$\begingroup\$ This looks a LOT like programming in Alice... \$\endgroup\$
    – mbomb007
    Apr 6, 2015 at 16:42
  • 4
    \$\begingroup\$ That's what you get with block based languages. Come to thing of it, lots of languages look alike. ;) \$\endgroup\$
    – Scimonster
    Apr 6, 2015 at 16:51
  • 1
    \$\begingroup\$ Even Scratch has a mod function so I'd assume that you could make the GCM/GCD function faster with a block based on if (b==0) then a else GCM(b, a%b) \$\endgroup\$
    – Alchymist
    Apr 7, 2015 at 10:57
58
\$\begingroup\$

2007 - LOLCODE

Language History

LOLCODE was created in 2007 by Adam Lindsay, a researcher at Lancaster University. Its syntax is based on the lolcats memes popularized by Cheezburger, Inc.

"Hello, World!" Variant

HAI
VISIBLE "LOLCODE wuz maed in 2007!"
KTHXBYE

ASCII Art N

HAI

BTW, read n from stdin
GIMMEH n

BTW, convert n from YARN to NUMBR
n R PRODUKT OF n AN 1

BOTH SAEM n AN 1, O RLY?
    YA RLY
        VISIBLE "N"
    NO WAI
        VISIBLE "N"!

        I HAS A butt ITZ 1
        IM IN YR toilet UPPIN YR butt TIL BOTH SAEM butt AN DIFF OF n AN 1
            VISIBLE " "!
        IM OUTTA YR toilet

        VISIBLE "N"

        I HAS A kat ITZ 2
        IM IN YR closet UPPIN YR kat TIL BOTH SAEM kat AN n
            VISIBLE "N"!
            BOTH SAEM kat AN 2, O RLY?
                YA RLY
                    VISIBLE "N"!
                NO WAI
                    I HAS A doge ITZ 1
                    IM IN YR l00p UPPIN YR doge TIL BOTH SAEM doge AN DIFF OF kat AN 1
                        VISIBLE " "!
                    IM OUTTA YR l00p
                    VISIBLE "N"!
            OIC

            I HAS A brd ITZ 1
            IM IN YR haus UPPIN YR brd TIL BOTH SAEM brd AN DIFF OF n AN kat
                VISIBLE " "!
            IM OUTTA YR haus

            VISIBLE "N"
        IM OUTTA YR closet

        VISIBLE "N"!

        I HAS A d00d ITZ 1
        IM IN YR lap UPPIN YR d00d TIL BOTH SAEM d00d AN DIFF OF n AN 1
            VISIBLE " "!
        IM OUTTA YR lap

        VISIBLE "N"
OIC

KTHXBYE

Values are read as strings (YARNs) from stdin using GIMMEH. They can be converted to numeric (NUMBRs) by multiplying by 1.

Values are printed to stdout using VISIBLE. By default a newline is appended, but it can be suppressed by adding an exclamation point.

GCD

HAI

GIMMEH a
a R PRODUKT OF a AN 1

GIMMEH b
b R PRODUKT OF b AN 1

I HAS A d00d ITZ 1
IM IN YR food UPPIN YR d00d TIL BOTH SAEM b AN 0
    I HAS A kitty ITZ a
    I HAS A doge ITZ b
    a R doge
    b R MOD OF kitty AN doge
IM OUTTA YR food

VISIBLE SMOOSH "gcd is " a

KTHXBYE

SMOOSH performs string concatenation.

\$\endgroup\$
5
  • 15
    \$\begingroup\$ Finally, a language everyone can understand. \$\endgroup\$ Apr 12, 2015 at 20:05
  • 31
    \$\begingroup\$ IM IN YR toilet UPPIN YR butt Nice variable names \$\endgroup\$
    – Cole Tobin
    Apr 13, 2015 at 2:51
  • 17
    \$\begingroup\$ @ColeJohnson: I always try to choose variable names that make sense in the situation rather than x1, x2, etc. \$\endgroup\$
    – Alex A.
    Apr 13, 2015 at 4:11
  • 2
    \$\begingroup\$ Hilarious. I should not read this at work. \$\endgroup\$ May 11, 2015 at 15:22
  • \$\begingroup\$ @AlanHoover: Clearly teh lolz are more important than teh jobz. \$\endgroup\$
    – Alex A.
    May 11, 2015 at 15:23
48
\$\begingroup\$

1982 - PostScript

PostScript is a language for creating vector graphics and printing.

Adobe was founded in 1982, and their first product was PostScript. The language was used in printers: the commands are interpreted by the printer to create a raster image, which is then printed onto the page. It was a very common component of laser printers well into the 1990s. But it’s obviously quite CPU intensive on the printer, and as computer processors became more powerful, it made more sense to do the rasterisation on the computer than the printer. PostScript has largely gone away on consumer printers, although it still exists on a lot of more high-end printers.

The standard which replaced PostScript is a little-known format called PDF.

PostScript had fallen out of fashion by the time I started programming, but I learnt a little bit while I was in university as another way of creating documents for TeX. It was quite different to other programming languages I’d used (reverse infix notation, stack, printing to a page instead of a console), but it was nice to dust off this old language for some fun.

Since PostScript is a printing language, it seems more appropriate to use it to print something then send an output to the console.

Task 1

/Courier findfont
12 scalefont
setfont
newpath

100 370 moveto
(PostScript was made in 1982!\n) show

The first few lines set up a canvas to draw on. Then the moveto command tells PS to draw at a particular position, and show prints the string to the page. Note that parentheses mark a string in PostScript, not quotation marks.

Task 2

/asciiartN {% stack: N row col
            % output: draws an "ASCII art" N

  % PostScript doesn't allow you to pass variables directly into a function;
  % instead, you have to pass variables via the global stack. Pop the variables
  % off the stack and define them locally.
  6 dict begin
  /row exch def
  /col exch def
  /N exch def

  % Define how much space will be between each individual "N"
  /spacing 15 def

  % Get the width of the "N". We need this to know where to draw the right-hand
  % vertical
  /endcol col spacing N 1 sub mul add def

  % One row is drawn at a time, with the bottom row drawn first, and working
  % upwards. This stack variable tracks which column the diagonal is in, and so
  % we start on the right and work leftward
  /diagcol endcol def

  % Repeat N times: draw one row at a time
  N {
    % Left-hand vertical of the "N"
    col row moveto
    (N) show

    % Right-hand vertical of the "N"
    endcol row moveto
    (N) show

    % Diagonal bar of the "N"
    diagcol row moveto
    (N) show

    % Advance to the next row. This means moving the row one space up, and the
    % diagonal position one place to the left.
    /row row spacing add def
    /diagcol diagcol spacing sub def

  } repeat

  end
} def

1 100 200 asciiartN
3 150 200 asciiartN
5 230 200 asciiartN

I wrote a function for drawing the “ASCII art” N, but there’s no way for PostScript functions to take an argument. Instead, you push your arguments to the stack, then get them back off. That’s the /x exch def line.

An example: suppose the stack is 8 9 2. First we push the name /x to the stack, so the stack is 8 9 2 /x. The exch operator swaps the two stack values, so now the stack is 8 9 /x 2. Then def pops the top two stack values, and defines /x to have the value 2. The stack is now 8 9.

When I started using PostScript, I found this a little confusing. I’d read about the stack as a theoretical concept, but this was the first time I was using it in practice.

The rest of the function is some drawing code: start at the bottom right-hand corner, filling in a row at a time from left-to-right-to-diagonal.

Task 3

/modulo {% stack: x y
         % output: returns (x mod y)
  3 dict begin
  /y exch def
  /x exch def

  % If x = y then (x mod y) == 0
  x y eq {0} {

    % If x < y then (x mod y) == x
    x y lt {x} {

      % If x > y then subtract floor(x/y) * y from x
      /ycount x y div truncate def
      /x x ycount y mul sub def

      /x x cvi def
      x

    } ifelse
  } ifelse
} def

/gcd {% stack: a b
      % returns the gcd of a and b
  2 dict begin
  /b exch def
  /a exch def

  % I'm using the recursive version of the Euclidean algorithm

  % If b = 0 then return a
  b 0 eq {a} {

    % Otherwise return gcd(b, a mod b)
    /a a b modulo def
    b a gcd
  } ifelse

} def

/displaygcd {% stack: a b xcoord ycoord
             % displays gcd(a,b) at position (xcoord, ycoord)
  5 dict begin
  /ycoord exch def
  /xcoord exch def
  /b exch def
  /a exch def
  /result a b gcd def

  xcoord ycoord moveto
  result 20 string cvs show

  % end
} def

8 12 100 80 displaygcd
12 8 150 80 displaygcd
3 30 200 80 displaygcd
5689 2 250 80 displaygcd
234 876 300 80 displaygcd

Again, I used a form of Euclid’s algorithm, but I’d forgotten that PostScript has a built in modulo operator, so I had to write my own. This turned out to be a useful reminder of the constraints of stack-based programming. My first implementation of modulo was based on recursion:

modulo(x, y)
    if (x = y) return 0
    elif (x < y) return x
    else return module(x - y, y)

which is fine until you try to run this when x is large and y is small (e.g. 5689 and 2). You can only have up to 250 elements on the stack, and so I was blowing well past the stack limit. Oops. I had to go back to the drawing board on that one.

The GCD code itself is fairly simple. But just as functions can’t take arguments, so they don’t have return values. Instead, you have to push the result to the stack where somebody else can pop it off later. That’s what the a and b a gcd lines do: when they’ve finished evaluating, they push the value to the stack.

If you put all the code in a document and print it, this is what the output looks like:

enter image description here

\$\endgroup\$
4
  • 9
    \$\begingroup\$ Haha I love the photograph of the printed piece of paper. Feels appropriate for 1982. \$\endgroup\$
    – Alex A.
    Apr 17, 2015 at 14:21
  • 1
    \$\begingroup\$ Also, thanks for your description of how you got a (literal) stack overflow--now I understand more intuitively why languages have a max recursion depth. \$\endgroup\$
    – DLosc
    Apr 17, 2015 at 21:11
  • 2
    \$\begingroup\$ @AlexA.: Yeah, but a dot-matrix printout (with holes on the sides of the paper) would've been even more appropriate. ;-) \$\endgroup\$ May 5, 2015 at 6:41
  • \$\begingroup\$ @AmosM.Carpenter: not really, I don't think any dot-matrix printer ever supported PostScript. It's always been pretty tied to laser printers. \$\endgroup\$
    – ninjalj
    Dec 29, 2017 at 11:40
42
\$\begingroup\$

2009 - ><>

Inspired by Befunge, ><> (Fish) is an esoteric stack-based 2D language, i.e. program flow can be up, down, left or right. The initial version of ><> featured multithreading where [ and ] created and ended threads, but for simplicity reasons these instructions were changed to creating and removing new stacks respectively.

The current official interpreter for ><> can be found here. Unfortunately, the link to the old interpreter on Esolang wiki is broken.

"Hello, World!" Variant

"!9002 ni edam saw ><>"l?!;obb+0.

Note how the string is written backwards — ><> doesn't technically have strings, with the only data type being a weird mix of char, int and float. " toggles string parsing, pushing each character onto the stack until a closing " is met.

The second half of the code then pushes the length of the stack l, checks if it's zero ?! and if so the program terminates ;. Otherwise the instruction pointer continues, outputting the top of the stack with o before executing bb+0., which teleports the pointer to position (22, 0) just before the l, creating a loop.

ASCII Art N

&0 > :&:&:*=?;  :&:&%  :0=?v  :&:&1-=?v  :{:{-&:&,{=?v   " " o   \

                           > ~"N"o                           v    
   +                                  > ~"N"oao              v    
   1                                                 >"N"o   v    

   \                                                         <   /

With spacing for clarity. You can try this out at the new online interpreter here and see the instruction pointer go around and around — just remember to enter a number in the "Initial Stack" textbox. If you're running via the Python interpreter, use the -v flag to initialise the stack, e.g.

py -3 fish.py ascii.fish -v 5

For this program, we put the input n into the register with & and push a 0, which we'll call i for "iterations". The rest of the program is a giant loop which goes like this:

:&:&:*=?;          If i == n*n, halt. Otherwise ...
:&:&%              Push i%n
:0=?v              If i%n == 0 ...
>~"N"o               Print "N"
:&:&1-=?v          Else if i%n == n-1 ...
>~"N"oao             Print "N" and a newline
:{:{-&:&,{=?v      Else if i%n == i//n, where // is integer division...
>~"N"o               Print "N"
" "o               Otherwise, print a space
1+                 Increment i

Then we repeat the loop from the beginning.

The arrows ^>v< change the direction of program flow and the mirrors /\ reflect the direction of program flow.

GCD

>:{:}%\
;n{v?:/
v~@/

Here's an example of what a golfed ><> program might look like. Once again, you can try this in the online interpreter (enter two comma-separated values in the "Initial stack" box, e.g. 111, 87) or by using the -v flag of the Python interpreter, e.g.

py -3 fish.py gcd.fish -v 111 87

This program uses the Euclidean algorithm. Here's a GIF I prepared earlier:

enter image description here

Note that ><> is toroidal, so when the bottom left v instruction is executed the instruction pointer goes downwards, wraps around, and reappears at the top.


Edit: By making the code run entirely from right to left, @randomra managed to shave three bytes with

<~@v!?:%}:{:
;n{/

Guess I didn't golf it down enough :)

\$\endgroup\$
1
  • 31
    \$\begingroup\$ And that was how I found out that the name ><> is a palindrome. \$\endgroup\$ Apr 9, 2015 at 11:54
33
\$\begingroup\$

2012 - Element

This is a language that I invented in early 2012 to be a simple golfing language. By this, I mean that there is very little to no operator overloading. The operators are also simpler and fewer in number than most modern golfing languages.

The most interesting features of this language are its data structures. There are two stacks and a hash that are used to store information.

The m-stack is the main stack, where arithmetic and most other operations take place. When data is inputted or printed, this is where it goes or is retrieved from.

The c-stack is the control stack. This is where boolean arithmetic takes place. The top values of the c-stack are used by If and While loops as the condition.

The hash is where variables are stored. The ; and ~ store and retrieve data from the hash, respectively.

Element is a very weakly typed language. It uses Perl's ability to freely interpret numbers as strings and vice-versa.

While I'm at it, I might as well include all the documentation for the language. You can find the original 2012 interpreter, written in Perl, right here. Update: I have created a more usable version, which you can find right here.

OP    the operator.  Each operator is a single character
STACK tells what stacks are affected and how many are popped or pushed
      "o" stands for "other effect"
HASH  tells if it involves the hash
x & y represent two values that are already on the stack, so the effect of
      the operator can be more easily described

OP     STACK  HASH   DESCRIPTION
text     ->m         --whenever a bare word appears, it pushes that string onto 
                       the main stack
_       o->m         --inputs a word and pushes onto main stack
`       m->o         --output.  pops from main stack and prints
xy;    mm->    yes   --variable assignment.  the top stack element y is assigned 
                       the value x
~       m->m   yes   --variable retrieval.  pops from main stack, pushes contents 
                       of the element with that name
x?      m->c         --test. pops x and pushes 0 onto control stack if x is '0' or 
                       an empty string, else pushes 1
><=     m->c         --comparison. pops two numbers off of stack and performs 
                       test, pushes 1 onto control stack if true and 0 if false
'       m->c         --pops from main stack and pushes onto control stack
"       c->m         --pops from control stack and pushes onto main stack
&|     cc->c         --AND/OR. pops two items from control stack, performs and/or 
                       respectively, and pushes result back onto control stack
!       c->c         --NOT. pops a number off of control stack, pushes 1 if 0 or 
                       empty string, 0 otherwise
[]       c           --FOR statement (view the top number number from control stack 
                       and eval those many times)
{}       c           --WHILE (loop until top number on control stack is 0, also 
                       does not pop)
#       m->          --discard. pops from main stack and destroys
(       m->mm        --pops from main stack, removes first character, pushes the 
                       remaining string onto stack, and pushes the removed character 
                       onto stack
)       m->mm        --pops from main stack, removes last character, pushes the 
                       remaining string onto stack, and pushes the removed character 
                       onto stack
+-*/%^ mm->m         --arithmetic. pops two most recent items, adds/negates
                       /multiplies/divides/modulates/exponentiates them, and places 
                       the result on the stack 
xy@    mm->o         --move. pops x and y and moves xth thing in stack to move to 
                       place y in stack
x$      m->m         --length. pops x and pushs length of x onto the stack
xy:    mm->o         --duplication. pops x and y and pushes x onto the stack y times
xy.    mm->m         --concatination. pops x and y and pushes x concatonated with y
\        o           --escapes out of next character, so it isn't an operator and can
                       be pushed onto the stack
,      m->mm         --character conversion. pops from main stack, coverts it to char
                       and pushes, and converts to num and pushes
Newlines and spaces separate different elements to be pushed 
onto the stack individually, but can pushed onto the stack using \

Task 1 - Print Text

Element\ was\ made\ in\ 2012\!`

One of the more awkward parts of the language is the lack of string delimiters, which is why escape characters are needed in this string. The ` at the end prints the string.

Task 2 - ASCII Art N

_+'[y~1+y;0[1+4:"2:'=1=|y~=|\ [#N]`"#]\
`]

Here, you will witness some stack manipulation. To make the explanation a little easier to format, I'll replace the newline with an L and the space with an S.

_+'[y~1+y;0[1+4:"2:'=1=|y~=|\S[#N]`"#]\L`]
_+'      input line, convert to #, move to c-stack
[        FOR loop
 y~1+y;  increment the y-pos
 0       set the x-pos (the top # on the stack) to zero
 [       FOR loop
  1+4:   increment x-pos and make 3 additional copies (4 is total #)
  "2:'   make a copy of the N size on the main stack
  =      if x-pos == size
  1=     or if x-pos == 1
  y~=|   of if x-pos == y-pos
  \S     (always) push a space
  [      the IF body (technically a FOR loop)
   #N    if true, remove the space and push an N
  ]      end IF
  `      output the pushed character
  "#     remove the result of the conditional
 ]       end x-pos FOR
 \L`     output a newline
]        end y-pos FOR

After doing some extreme golfing of this answer, I found a 39 byte solution, although it is much more complicated.

_'1[y~+y;[#1+3:"2:'%2<y~=|\ [#N]`"]\
`]

Task 3 - GCD

__'{"3:~2@%'}`

This is a stack-based method.

__                 input the two numbers
  '                use one of the number as a condition so the WHILE loop starts
   {        }      a WHILE loop. Repeats while the c-stack has a true value on top
    "              get the number back from the c-stack to do operations on it
     3:            make it so that there are threes copies on the stack
       ~           takes one of the copies from earlier and converts it to a zero
        2@         take the top item on the stack and move it behind the other two #s
          %        modulo operation
           '       use this number as the condition
             `     since one number is zero (and on the c-stack) print the 
                   other number, which is on m-stack
\$\endgroup\$
0
30
\$\begingroup\$

2012 - Julia

Language History

Julia was developed in 2012 by Jeff Bezanson, Stefan Karpinski, and Viral Shah while Jeff was a student at the Massachussets Institute of Technology (MIT), advised by professor Alan Edelman. They were motivated by a desire for a programming language that was open source, fast, and dynamic (among many other things) while maintaining ease of use in a variety of applications. The product was Julia, a fresh approach to high performance scientific computing.

"Hello, World!" Variant

println("Julia was made in 2012!")

Printing to STDOUT in Julia is quite simple!

ASCII Art N

function asciin(n)
    # Create an nxn matrix of spaces
    m = fill(" ", (n, n))

    # Fill the first and last columns with "N"
    m[:,1] = m[:,n] = "N"

    # Fill the diagonal elements with "N"
    setindex!(m, "N", diagind(m))

    # Print each row of the matrix as a joined string
    for i = 1:n
        println(join(m[i,:]))
    end
end

The code is indented for readability, but Julia imposes no restrictions on whitespace.

GCD

function g(a, b)
    b == 0 ? a : g(b, a % b)
end

The last thing listed in the function is implicitly returned.

\$\endgroup\$
0
29
\$\begingroup\$

1988 - Mathematica

Or should I call it Wolfram Language?

Task 0

The creator of Mathematica is Stephen Wolfram, the Founder and CEO of Wolfram Research. Before the development of Mathematica, he was a physicist. There was a huge amount of algebraic calculation in physics, so he became a user of Macsyma.

Wolfram got his PHD in 1979, when he was 20. He thought that he needed a better CAS than Macsyma to do physics, so he began to write SMP (the "Symbolic Manipulation Program"). The first version of SMP was released in 1981. SMP was the predecessor of Mathematica. Though it had a deep influence on Mathematica, none of its code was ever used for Mathematica.

In 1986, Wolfram decided to write an "ultimate computation system". He started writing the code in 1986, and founded the Wolfram Research in 1987. Finally, Mathematica 1.0 was released on June 23, 1988.

Mathematica 1.0

I didn't find Mathematica 1.0. In fact, Mathematica 1.0 had neither a Windows nor a Linux version. But I found Mathematica 2.0 on a Chinese website. It can still be run on Windows XP.

Mathematica 2.0

Task 1

Print["Mathematica was made in 1988!"]

Or simply:

"Mathematica was made in 1988!"

Task 2

In today's Mathematica, we can write:

asciiArtN[n_] := Print @@@ SparseArray[{i_, 1 | i_ | n} -> "N", {n, n}, " "]

Just like Julia and R, this is a matrix solution. In Mathematica, you can define a sparse matrix using pattern matching.

However, SparseArray was introduced in Mathematica 5.0, so we can't use it in Mathematica 1.0.

Here is a solution that works in Mathematica 1.0:

asciiArtN[n_] := Block[{f},
  f[i_, 1]  = "N";
  f[i_, i_] = "N";
  f[i_, n]  = "N";
  f[__]     = " ";
  Apply[Print, Array[f, {n, n}], 1];
]

We can't write f[i_, 1 | i_ | n] = "N" because Alternatives was introduced in Mathematica 2.0.

Task 3

We can just use the built-in function:

gcd = GCD

Or we can use the definition of the GCD:

gcd = Max[Intersection @@ Divisors[{##}]] &;

Or we can use the LCM, though more commonly LCM is computed from GCD:

gcd = Times[##]/LCM[##] &;

Or we can use the Euclidean algorithm with pattern matching:

gcd[a_, 0] := a
gcd[a_, b_] := gcd[b, Mod[a, b]]

Or as an anonymous function:

gcd = If[#2 == 0, #1, #0[#2, Mod[##]]] &;

All the functions above were introduced in Mathematica 1.0.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ This is a much better answer than mine. I'll delete mine. \$\endgroup\$ Apr 16, 2015 at 13:55
25
\$\begingroup\$

1972 - INTERCAL

And you thought Fortran and Cobol were weird. This is insane!

Task 1

DO ,1 <- #27
DO ,1SUB#1 <- #110
DO ,1SUB#2 <- #32
DO ,1SUB#3 <- #72
PLEASE DO ,1SUB#4 <- #136
DO ,1SUB#5 <- #88
DO ,1SUB#6 <- #136
PLEASE DO ,1SUB#7 <- #64
DO ,1SUB#8 <- #80
DO ,1SUB#9 <- #46
PLEASE DO ,1SUB#10 <- #22
DO ,1SUB#11 <- #104
DO ,1SUB#12 <- #184
PLEASE DO ,1SUB#13 <- #202
DO ,1SUB#14 <- #78
DO ,1SUB#15 <- #48
PLEASE DO ,1SUB#16 <- #96
DO ,1SUB#17 <- #128
DO ,1SUB#18 <- #162
PLEASE DO ,1SUB#19 <- #110
DO ,1SUB#20 <- #32
DO ,1SUB#21 <- #114
PLEASE DO ,1SUB#22 <- #120
DO ,1SUB#23 <- #240
DO ,1SUB#24 <- #128
PLEASE DO ,1SUB#25 <- #208
DO ,1SUB#26 <- #200
DO ,1SUB#27 <- #52
DO READ OUT ,1
DO GIVE UP

I'm not going to try to explain INTERCAL's system of input and output; just read this and hope you don't die.

Task 2

DO WRITE IN 7
DO .1 <- .7
DO .2 <- #1
PLEASE DO (1010) NEXT
DO .8 <- .3
DO .5 <- .7
DO .6 <- .8
DO ,9 <- #2

DO (100) NEXT
DO (1) NEXT

(100) DO (99) NEXT
DO ,9SUB#1 <- #142
DO ,9SUB#2 <- #114
PLEASE DO READ OUT ,9
DO ,9SUB#1 <- #176
DO ,9SUB#2 <- #80
PLEASE DO READ OUT ,9
PLEASE GIVE UP

(99) DO .1 <- .7
DO .2 <- #1
PLEASE DO (1010) NEXT
DO .1 <- '.3~.3'~#1
PLEASE DO FORGET .1
DO RESUME #1

(1) PLEASE DO (3) NEXT
PLEASE DO FORGET #1
DO (1) NEXT

(3) DO (4) NEXT
PLEASE GIVE UP

(4) DO (8) NEXT
DO ,9SUB#1 <- #176
DO ,9SUB#2 <- #80
PLEASE DO READ OUT ,9
DO .6 <- .8
DO .1 <- .5
DO .2 <- #1
DO (1010) NEXT
DO .5 <- .3
DO .1 <- '.5~.5'~#1
PLEASE DO FORGET .1
DO RESUME #1

(8) DO (5) NEXT

(5) PLEASE DO (6) NEXT
PLEASE DO FORGET #1
DO (5) NEXT

(6) PLEASE DO (7) NEXT
DO RESUME #2

(7) DO (10) NEXT
DO .1 <- .6
DO .2 <- #1
PLEASE DO (1010) NEXT
DO .6 <- .3
DO .1 <- '.6~.6'~#1
PLEASE DO FORGET .1
DO RESUME #1

(10) DO (11) NEXT
DO (13) NEXT
DO (14) NEXT
DO (15) NEXT

(11) DO (111) NEXT
DO (112) NEXT

(13) DO (113) NEXT
DO (112) NEXT

(14) DO (114) NEXT
DO (112) NEXT

(111) DO .1 <- .6
DO .2 <- .8
DO (1010) NEXT
DO .1 <- '.3~.3'~#1
PLEASE DO FORGET .1
DO RESUME #1

(112) DO ,9SUB#1 <- #142
DO ,9SUB#2 <- #114
PLEASE DO READ OUT ,9
DO RESUME #3

(113) DO .1 <- .6
DO .2 <- #1
DO (1000) NEXT
DO .1 <- .5
DO .2 <- .3
DO (1010) NEXT
DO .1 <- '.3~.3'~#1
PLEASE DO FORGET .1
DO RESUME #1

(114) DO .1 <- '.6~.6'~#1
PLEASE DO FORGET .1
DO RESUME #1

(15) DO ,9SUB#1 <- #252
DO ,9SUB#2 <- #4
PLEASE DO READ OUT ,9
DO RESUME #2

Goodness gracious. This took me a bit to figure out. The label numbers are a mess and therefore reflect that. I'm not going to try to explain this unless someone asks.

Task 3

DO WRITE IN .5
DO WRITE IN .6

DO (1) NEXT

(1) PLEASE DO (3) NEXT
DO FORGET #1
DO (1) NEXT

(3) DO (4) NEXT
DO READ OUT .5
PLEASE GIVE UP

(4) DO .1 <- .5
DO .2 <- .6
PLEASE DO (1040) NEXT
DO .1 <- .3
DO .2 <- .6
PLEASE DO (1039) NEXT
DO .2 <- .3
DO .1 <- .5
DO (1010) NEXT
DO .5 <- .6
DO .6 <- .3
DO .1 <- '.6~.6'~#1
PLEASE DO FORGET .1
DO RESUME #1

This one's a tad simpler. Because of INTERCAL's...weirdness, you have to enter the numbers like this:

THREE FIVE

For instance, to get the GCD of 42 and 16, I'd enter:

FOUR TWO
ONE SIX

It also prints the number in Roman numerals...because that's INTERCAL for you!

\$\endgroup\$
5
  • 2
    \$\begingroup\$ Shouldn't it be 1972? (I can understand if you're a bit dizzy after writing this :P) Your answer is considered invalid due to this mistake, which would be a shame. \$\endgroup\$
    – marinus
    Apr 28, 2015 at 21:15
  • \$\begingroup\$ @marinus Thank you! Fixed! \$\endgroup\$ Apr 28, 2015 at 21:35
  • 5
    \$\begingroup\$ PLEASE DO explain. (When you have time, of course. ;) \$\endgroup\$
    – DLosc
    May 2, 2015 at 5:18
  • 1
    \$\begingroup\$ INTERCAL is my favourite language that I've never learnt! \$\endgroup\$
    – CJ Dennis
    May 2, 2015 at 11:59
  • 1
    \$\begingroup\$ PLEASE GIVE UP. I did it already .-. \$\endgroup\$
    – RedClover
    Dec 29, 2017 at 18:18
25
\$\begingroup\$

1999 - XSLT

The World Wide Web Consortium (W3C) created XSLT for transforming XML into HTML, text, etc. The following examples assume input is enclosed in <input>..</input> tags.

Task 1

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" indent="no"/>
  <xsl:template match="/input">XSLT was made in 1999!</xsl:template>
</xsl:stylesheet>

This one is simple. It matches an input tag at the top level and replaces it with the desired output.

Task 2

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" indent="no"/>
  <xsl:template match="/input">
    <xsl:call-template name="loop">
      <xsl:with-param name="i">1</xsl:with-param>
      <xsl:with-param name="n">
        <xsl:value-of select="."/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:template>
  <xsl:template name="loop">
    <xsl:param name="i"/>
    <xsl:param name="n"/>
    <xsl:choose>
      <xsl:when test="$i = 1 or $i = $n">
        <xsl:text>N</xsl:text>
        <xsl:call-template name="spaces">
          <xsl:with-param name="n">
            <xsl:value-of select="$n - 2"/>
          </xsl:with-param>
        </xsl:call-template>
        <xsl:text>N&#13;&#10;</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>N</xsl:text>
        <xsl:call-template name="spaces">
          <xsl:with-param name="n">
            <xsl:value-of select="$i - 2"/>
          </xsl:with-param>
        </xsl:call-template>
        <xsl:text>N</xsl:text>
        <xsl:call-template name="spaces">
          <xsl:with-param name="n">
            <xsl:value-of select="$n - $i - 1"/>
          </xsl:with-param>
        </xsl:call-template>
        <xsl:text>N&#13;&#10;</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
    <xsl:if test="$i &lt; $n">
      <xsl:call-template name="loop">
        <xsl:with-param name="i">
          <xsl:value-of select="$i + 1"/>
        </xsl:with-param>
        <xsl:with-param name="n">
          <xsl:value-of select="$n"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
      <xsl:template name="spaces">
    <xsl:param name="n"/>
    <xsl:if test="$n &gt; 0">
      <xsl:text> </xsl:text>
      <xsl:call-template name="spaces">
        <xsl:with-param name="n">
          <xsl:value-of select="$n - 1"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

This one defines 2 recursive templates, loop and spaces. loop with parameters i and n will generate the desired output for n, starting at position i. spaces with parameter n will generate n spaces.

Task 3

Input for this must be in <input><num>..</num><num>..</num></input> tags.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" indent="no"/>
  <xsl:template match="/input">
    <xsl:call-template name="gcd">
      <xsl:with-param name="a"><xsl:value-of select="num[1]"/></xsl:with-param>
      <xsl:with-param name="b"><xsl:value-of select="num[2]"/></xsl:with-param>
    </xsl:call-template>
  </xsl:template>
  <xsl:template name="gcd">
    <xsl:param name="a"/>
    <xsl:param name="b"/>
    <xsl:choose>
      <xsl:when test="$b = 0"><xsl:value-of select="$a"/></xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="gcd">
          <xsl:with-param name="a"><xsl:value-of select="$b"/></xsl:with-param>
          <xsl:with-param name="b"><xsl:value-of select="$a mod $b"/></xsl:with-param>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

This one is just a recursive template gcd that uses the Euclidean algorithm.

\$\endgroup\$
2
  • \$\begingroup\$ And they say INTERCAL is weird! \$\endgroup\$ Aug 18, 2015 at 19:44
  • 2
    \$\begingroup\$ @kirbyfan64sos To be fair, it shouldn't be used for this stuff anyways... \$\endgroup\$ Aug 20, 2015 at 1:12
24
\$\begingroup\$

2014 - CJam

CJam was created by PPCG user aditsu and was released around April 2014.

"Hello, World!" Variant

"CJam was made in 2014!"

CJam automatically prints the contents of the stack at the end of the program

ASCII Art N

ri:R'#*a_R2-,{_)S*'#+\R((-zS*+}%+\+R<zN*

Code explanation:

ri:R                                       "Read the input as integer in R";
    '#*a                                   "Get a string of R # and wrap it in an array";
        _R2-,{                }%           "Copy that string and then run this loop R-2";
                                           "times for the diagonal";
              _)S*                         "Get iteration index + 1 spaces";
                  '#+                      "Append the hash";
                     \R((-zS*+             "Append remaining spaces";
                                +\+        "Append and prepend the initial # string";
                                   R<      "Take only R columns/rows. This is for";
                                           "tackling input 1";
                                     zN*   "Transpose and join with new lines";

Takes the height/width of N as input via STDIN. Try it online here

GCD

l~{_@\%}h;

Takes the two numbers as input via STDIN. Try it online here

\$\endgroup\$
1
  • \$\begingroup\$ I realize this isn't [code-golf], but you can shorten the ASCII-art N program to ri_S*0'NtW'Nta1$*\,Sf*'Nf+..e>N* in modern CJam. \$\endgroup\$ Jun 10, 2018 at 7:16
24
\$\begingroup\$

1990 - Haskell

Haskell is a popular (or should I say: the most popular?) pure functional language. It sticks out from the mainstream by its unusual evaluation model (by default, everything is lazy or, technically, non-strict) and by its Hindley-Milner based type system which, even now, is still amongst the most powerful out there.

Task 1

main = putStrLn "Haskell was made in 1990!"

Task 2

-- Infinite list of growing letters 'N'
bigNs :: [[[Char]]]
bigNs = ["N"]
      : ["NN","NN"]
      : [ ins (ins 'N' t) $ map (ins ' ') n | n@(t:_) <- tail bigNs ]

-- Insert a new element after the head (i.e. at the second position).
ins :: a -> [a] -> [a]
ins x (l:ls) = l:x:ls

Demo, print the whole infinite list (until user aborts, or the world ends...)

GHCi> mapM_ (putStrLn . unlines) bigNs
N

NN
NN

N N
NNN
N N

N  N
NN N
N NN
N  N

N   N
NN  N
N N N
N  NN
N   N

N    N
NN   N
N N  N
N  N N
N   NN
N    N

...

Of course, you can easily get to a single one of these, by accessing only one element of the infinite list:

main :: IO ()
main = do
   i <- readLn
   putStrLn . unlines $ bigNs!!i

Task 3

gcd' :: Integer -> Integer -> Integer
gcd' a 0 = a
gcd' a b = gcd' b $ a`mod`b
\$\endgroup\$
24
\$\begingroup\$

1967 - APL

In 1957, at Harvard University, Ken Iverson started developing a mathematical notation for array manipulation. During the 1960s, his notation was developed into a programming language at IBM. The first partial implementation was created in 1963, and it was even used in a high school to teach students about transcendental functions. A full, usable implementation had to wait until 1965. For two years it was only used internally by IBM. In 1967, IBM released to the public an APL interpreter that ran on the IBM 1130 computer, which had been finished in 1966. You can understand how it's a bit hard to choose a year for it, however, I think it should be 1967, as this is the first year a full implementation was made available to the public. If anyone really disagrees, I could change it.

The source code for APL\360, is online, as is an emulator. This is what I have used to test these examples. It dates from 1967, and along with APL\1130 (for the aforementioned IBM 1130) it is more or less the true original. As expected, it is very primitive. It lacks support for such niceties as lowercase letters, any operators only work with builtin functions, and the set of builtin functions is very sparse (in particular, is only or, and does not double as gcd). The original, full description is available here, however, I noticed that the version I had is not even complete with respect to that document, lacking among others.

I have provided the programs both in Unicode format (so you can read them), and in the original encoding (so you can cut and paste them into the emulator's APL window).

Unbelievably, these programs run correctly without any changes (except for the encoding) in modern versions of Dyalog, NARS2000, and GNU APL. So I guess I've found the way to write portable APL: just pretend it's 1967!

Task 1:

Unicode:

⎕←'APL WAS MADE IN 1967!'

APL\360:

L[Kapl was made in 1967ÝK

Task 2:

Unicode:

⎕←' N'[1+((2⍴N)⍴(⍳N)∊1,N)∨(⍳N)∘.=⍳N←⎕]

APL\360:

L[K nK;1-::2Rn"R:In"E1,n"(:In"J.%In[L'

Task 3:

I have solved this the standard recursive way. In theory, you could do something clever and array-oriented, like the J answer; in practice, however, that has O(N) memory usage and quickly overwhelms Flower-Power-era hard- and software.

Unicode:

∇R←A GCD B
R←A
→(B=0)/0
R←B GCD B|A
∇

⎕←⎕ GCD ⎕

APL\360:

Gr[a gcd b
r[a
{:b%0"/0
r[b gcd bMa
G

L[L gcd L
\$\endgroup\$
1
  • \$\begingroup\$ This is awesome. \$\endgroup\$
    – Alex A.
    May 11, 2015 at 0:23
23
\$\begingroup\$

2005 - Prelude

Prelude is a very fun language, whose source code consists of several "voices" which are executed in parallel and which I really enjoy solving problems in. It is meant to be the ASCII representation of its sister language Fugue, which actually takes .midi files as its source code and encodes the instructions found in Prelude as intervals in the melodies of the voices.

Prelude is fairly minimalistic, yet Turing complete (provided you are using at least 2 voices). As I said, the voices (lines of code) are executed simultaneously, column by column. Each voice operates on its own stack, which is initialised to an infinite number of zeroes. Prelude supports the following instructions:

0-9 ... Push the corresponding digit.
+   ... Add the top two numbers on the stack.
-   ... Subtract the top number from the one beneath.
#   ... Discard the top of the stack.
^   ... Copy the top value from the voice above.
v   ... Copy the top value from the voice below.
?   ... Read a number and push it onto the stack.
!   ... Print the top number (and pop it from the stack).
(   ... If the top of the stack is zero, jump past the matching ')'.
)   ... If the top of the stack is zero, jump to the column after the matching '('.

Some additional notes:

  • The voices are cyclic, so ^ on the top voice copies from the bottom voice (and vice versa).
  • Multiple ? and ! in the same column are executed top to bottom.
  • As per the language specification, ? and ! read and write characters with the corresponding character code. However, the Python interpreter also has a switch in its code to print the numbers themselves instead. For testing purposes I am actually using a modified version which can also read numbers instead of characters. But consensus around here is that numerical input/output can actually be given as byte values, hence these modifications are not necessary to make valid programs dealing with numbers.
  • Matching ( and ) do not need to be on the same voice. The voice used for the condition is always the one where the ( appears. Hence, the vertical position of the ) is completely irrelevant.
  • Due to the nature of Prelude's simultaneous execution, any instruction in the same column as a ( is executed only once before the loop starts, and regardless of whether the loop is entered. Similarly, any instruction in the same column as a ) is executed at the end of each iteration, regardless of whether the loop will be exited after this iteration.

I'll first show you the three programs without much commenting. You can find extensive explanations below.

The Programs

"Hello, World!" Variant

9(1-)v98+^++!9v+!  v88++2+!^  ! ^9-3-! v      !    v2-!55+!
8 8+ !     7v+! 1v+!88+^+!^4-!^ v8-^ !!!9v+  !^9+9+!  v5+!
     ^98++4+! ^8-! ^4-   ^ #!^6-!    ^^  #5+! v    ^2-!1+!

If you are using the Python interpreter, make sure that NUMERIC_OUTPUT = False.

ASCII Art N

      v2-(1-)v         
9(1-)?1-( v!  (1-55+!      0     (0)#  ))55+!
4-4+                  v^-#
     v!      v! v1-v!(1- ^(#^!0)# v! )v!
6 8+           v#

For ease of use, this program benefits from reading input as numbers, but output must not be numeric. So if you are using the modified Python interpreter, set

NUMERIC_INPUT = True
NUMERIC_OUTPUT = False

GCD

?(                         v)
? (^-(0 # v   #       ^+0)#^ !
     ^^ (##v^v+)#  0 (0 )   
      1) ^ #  - 1+(#)#

This is best used with all numeric input/output i.e.

NUMERIC_INPUT = True
NUMERIC_OUTPUT = True

Explanations

"Hello, World!" Variant

This is fairly straight-forward. I'm using 3 voices to successively generate the character codes for all the characters in Prelude was made in 2005!. I start by computing 8 + 9*8 = 80, which is the character code of P:

 9(1-)
 8 8+

After that I mostly just copy the previous character code and add or subtract the difference to the next one. Here is the code, but with each ! replaced with the character that is being printed (and _ for spaces and % for the digits):

9(1-)v98+^++r9v+u  v88++2+w^  _ ^9-3-a v      _    v2-%55+!
8 8+ P     7v+l 1v+e88+^+_^4-s^ v8-^ de_9v+  n^9+9+%  v5+%
     ^98++4+e ^8-d ^4-   ^ #a^6-m    ^^  #5+i v    ^2-%1+!

The final 55+! prints a trailing newline, just because it's nicer.

As a side note, the number of voices is pretty arbitrary for this task, but 3 is fairly convenient because it's the largest number in which every voice can directly access each other voice.

ASCII Art N

      v2-(1-)v         
9(1-)?1-( v!  (1-55+!      0     (0)#  ))55+!
4-4+                  v^-#
     v!      v! v1-v!(1- ^(#^!0)# v! )v!
6 8+           v#

With 5 voices, this is definitely one of the most complex programs I've written so far. The voices roughly have the following purposes:

  1. Merely a helper voice which stores N-1 for use in the inner loop.
  2. This is sort of the "main" voice, which reads input, contains an important switch and also contains the outer loop (i.e. the one over the rows).
  3. This stores a 32 to conveniently print spaces.
  4. This contains the inner loop (the one over the columns).
  5. This stores a 78 to conveniently print Ns.

Let's go through the code part by part. First, I'm creating the 32 as -4 + 9*4 and the 78 as 6 + 9*8:

9(1-)
4-4+

6 8+

Now I'm printing a single N (because we always need one) while reading the input N and storing N-1 and N-2 in the first two voices:

      v2-
     ?1-

     v!

Next, there is a "loop" conditioned on N-1. At the end of the loop, the second voice is always reduced to 0, and the loop exits after the first iteration. So essentially, this only if(N > 1){...}. After the loop we print a single trailing newline. To recap, we've now got the following framework:

      v2-
9(1-)?1-(                               )55+!
4-4+
     v!
6 8+

Inside this conditional, we first N-2 spaces and a single N to complete the first row, and we also store N-1 on the first voice for future use:

         (1-)v         
          v!  

             v!

Now the real meat of the code. First, there is an outer loop, which prints N-1 rows. For each row, we first print a newline, and an N. Then we loop N-2 times, printing either spaces or Ns (more on that later). And finally we print another N:

               1-55+!  

                v1-v!(               )v!
               v#

Finally, the fun part: printing each row (and getting the position of the N right). There is not really an if/else in Prelude, so I have to build it myself using two loops on different voices. The condition can easily be obtained by subtracting the inner and outer loop variable - we get 0 if we want to print N and something non-zero if we want to print a space.

The basic idea of an if/else in Prelude is to put a loop after the relevant value - the "if" (or non-zero) code, and exit it immediately by pushing a 0. On another voice, you keep a non-zero value, and another loop after the "if" loop. During the "if" loop you put a zero on top of that other voice, so as to prevent the "else" from being executed. There is some flexibility in whether you push zero values on top of non-zero values or simply discard the non-zero value if there's a zero beneath, but this is the general idea. You might also have to do some cleanup afterwards, if you want to keep using the relevant voice. This is what the code looks like:

                           0     (0)#
                      v^-#
                      1- ^(#^!0)# v! 

And that's it!

GCD

This is "just" an iterative implementation of the Euclidean algorithm. But modulo in Prelude is a bit annoying, mostly because you can't easily check if a number is positive or negative. This code makes use of a signum implementation I wrote a while ago. I.e. a large part of the code just turns a number into -1, 0 or 1. This can then easily be turned into a condition for positive or negative numbers by adding or subtracting 1.

?(                         v)
? (^-(0 # v   #       ^+0)#^ !
     ^^ (##v^v+)#  0 (0 )   
      1) ^ #  - 1+(#)#

So we've got four voices this time. The first voice simply keeps track of b and contains the main termination condition (i.e. the loop exits when b becomes 0). The second voice contains a and with the help of voices three and four computes a % b, before swapping the result with the previous b. Finally, the ! prints a when b == 0.

Let's look at the signum part first:

     (0 # v   #
     ^^ (##v^v+)#
      1) ^ #  -

The input number n is found on the first of those voices (the second voice in the full program). The result will end up on the bottom voice. The other two voices are expected to be empty (i.e. filled with zeroes). Notice that, if n == 0, then both loops are skipped and the bottom voice still contains 0, just what we want.

If n is non-zero, the first small loop is entered. We push a zero to exit it immediately, put two copies of n onto the middle voice and a 1 onto the bottom voice. Now the basic idea is to increment one of the copies of n while decrementing the other copy of n until one of them hits zero. While doing so, the 1 on the bottom voice flips its sign all the time (which is easily done by subtracting it from 0 beneath it on the stack). This is set up such that when one of the numbers hits zero, the bottom voice will contain the correct sign.

Now modulo is implemented by subtracting b from a until the result is negative. When that happens, we add one b again. That's this bit:

  (^-  signum         ^+0)#
       signum      0 (0 )   
       signum   1+(#)#

Notice the if/else construction at the bottom, which is similar to the one I used for Task 2.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ This should really be part of a Prelude tutorial. \$\endgroup\$
    – Alex A.
    May 6, 2015 at 20:37
22
\$\begingroup\$

1996 - Ocaml

Was waiting more than day to someone fill 1996, so I could fill in Ruby. Well why not learn OCaml then, seems similar to haskell...

Hello world

print_endline "OCaml was made in 1996!";;

ASCII

let ascii n =
  let rec ascii' = function
    | 0 -> ()
    | i ->
        let s = "N" ^ String.make (n-2) ' ' ^ "N" in
        String.fill s (n-i) 1 'N';
        print_endline s;
        ascii' (i-1)
  in ascii' n;;

Mutable strings!

GCD

let rec gcd a b = if b = 0 then a else gcd b (a mod b);;

No == and infix mod, that's cute

\$\endgroup\$
3
  • \$\begingroup\$ I'm sorry, I filled in Ruby :) \$\endgroup\$
    – Zero Fiber
    Apr 14, 2015 at 12:14
  • 4
    \$\begingroup\$ +1 for learning a language just to answer this challenge. :) \$\endgroup\$
    – Alex A.
    Apr 14, 2015 at 15:45
  • \$\begingroup\$ You just learned F#, too! (it's OCaml on the CLR plus some extras). \$\endgroup\$ Apr 29, 2015 at 3:26
21
\$\begingroup\$

2007 - Scratch

Scratch is a language made by MIT for educational purposes. I've been very involved with it for 5 years; more on that later.

All of these can be viewed here.

I'm very rushed right now and will explain the snippets later. Hopefully they're prety self-explanatory though.

Task 1

enter image description here

Task 2

enter image description here

Task 3

enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ Is it later yet? \$\endgroup\$
    – dfeuer
    Mar 14, 2019 at 21:02
21
\$\begingroup\$

1972 - C

We all know about C, don't we? C was created at Bell Labs, along with Unix. Unix was largely written in C. All modern Unix derivatives are still largely written in C. C's syntax has influenced many, many programming languages. It is probably the oldest programming language that is still in widespread use for new development.

C itself is a descendant of B, which I hope will end up in this list as well. There was no 'A' programming language: B is a variant of BCPL, which in turn is a stripped down CPL. None of these languages were ever very popular. However, BCPL was the language in which the first "Hello World" program was written. Another interesting fact is that B had both /* */ and // comments, but C dropped the // comments. They were later reintroduced into C with the C99 standard.

The C programs here were tested with the Unix V5 C compiler, from 1974. This was the oldest C compiler I could find and get to work, and these programs will not compile on a modern C compiler. (One of the changes made is that mutation operators like += used to be written =+.)

#include <...> did not exist yet. Neither did much of the standard library. I had to write my own atoi. I went through some of the V5 source code to figure out which things were allowed and which were not. The version I used was the first to include structs, but since I did not use those, and the syntax doesn't seem to have changed a lot until V7 (as K&R C), this might work with earlier versions as well.

I have done my best to write my code in the same style as the V5 source code uses. (Not that that is terribly consistent, though.)

Look here for links to Unix V5, an emulator, and instructions on getting it running on a modern computer.

Task 1

main()
{
   write(1, "C was made in 1972!\n", 20);
}

Task 2

atoi(str)
char *str;
{
    register num, digit;
    while (digit = *str++) {
        num =* 10;
        num =+ digit - '0';

    }
    return num;
}

N(n)
{
    register x, y;
    for (y=1; y<=n; y++) {
        for (x=1; x<=n; x++) {
            write(1, " N"+(x==1||x==y||x==n), 1);
        }
        write(1, "\n", 1);
    }
}

main(argc, argv)
char *argv[];
{
    N(atoi(argv[1]));
}

Task 3

atoi(str)
char *str;
{
    register num, digit;
    while (digit = *str++) {
        num =* 10;
        num =+ digit - '0';
    }
    return num;
}

gcd(a, b)
{
    return b ? gcd(b, a%b) : a;
}

main(argc, argv)
char *argv[];
{
    printf("%d\n", gcd(atoi(argv[1]), atoi(argv[2])));
}
\$\endgroup\$
3
  • \$\begingroup\$ Wow, I never realized how much C has changed... Where did you get that compiler from? \$\endgroup\$ Apr 29, 2015 at 15:22
  • 1
    \$\begingroup\$ The compiler is the one included with Unix V5. There's a link in the description to a blog post that shows you where to get the files and how to run it on a modern computer. (It's here). Once you have it running, you can get the code onto it using cat > file.c. (End with Ctrl-D, as always). Also, C has changed less than you might think: if you swap the =* and =+ in the atoi functions for the modern equivalents *= and +=, a modern GCC will compile them just fine and they run, too. Hardly any warnings, even. \$\endgroup\$
    – marinus
    Apr 29, 2015 at 15:36
  • 2
    \$\begingroup\$ minnie.tuhs.org/cgi-bin/utree.pl?file=V2/c is the earliest C compiler I could find (from V2, dated '72). \$\endgroup\$
    – Oberon
    May 11, 2015 at 14:23
20
\$\begingroup\$

2009 - Idris

Idris is a dependantly-typed, pure functional language that emphasises being in fact practically usable for real-world applications, apart from offering the extremely rigorous proof possibilities that are achievable with dependant types.

Task 1

module Main

main : IO ()
main = putStrLn "Idris was made in 2009!"

Task 2

module InN

import Data.Fin
import Data.Vect

genN : Vect n (Vect n Char)
genN = [[ if inN x y then 'N' else ' ' | x<-range ]| y<-range ]

||| Helper function, determines whether the char at coordinate (x,y)
||| is part of the letter:
inN : Fin n -> Fin n -> Bool
inN {n=S _} x y = x==0 || x==y || x==last

This one is not a program but just a function (more precisely, dependant value), producing the desired letter N as a two-dimensional array.

$ idris ascii-n.idr 
     ____    __     _                                          
    /  _/___/ /____(_)____                                     
    / // __  / ___/ / ___/     Version 0.9.17.1-
  _/ // /_/ / /  / (__  )      http://www.idris-lang.org/      
 /___/\__,_/_/  /_/____/       Type :? for help               

Idris is free software with ABSOLUTELY NO WARRANTY.            
For details type :warranty.
Type checking ./ascii-n.idr
*ascii-n> genN {n=4}
[['N', ' ', ' ', 'N'],
 ['N', 'N', ' ', 'N'],
 ['N', ' ', 'N', 'N'],
 ['N', ' ', ' ', 'N']] : Vect 4 (Vect 4 Char)

Task 3

module gcd

gcd' : Nat -> Nat -> Nat
gcd' a Z = a
gcd' a b = gcd' b $ a`mod`b

Note that I had to choose the name gcd' because as gcd it is already defined in the Idris prelude.

Type checking ./gcd.idr
*gcd> gcd' 8 12
4 : Nat
*gcd> gcd' 12 8
4 : Nat
*gcd> gcd' 234 876
6 : Nat
\$\endgroup\$
3
  • \$\begingroup\$ That looks like they took Haskell, swapped : and ::, and changed _ to Z. \$\endgroup\$
    – wchargin
    Apr 11, 2015 at 21:22
  • \$\begingroup\$ @WChargin Z is actually the constructor of 0 : Nat. The underscore is used in Idris just like it is in Haskell. \$\endgroup\$ Apr 11, 2015 at 23:45
  • \$\begingroup\$ oh, well, there you go! :) \$\endgroup\$
    – wchargin
    Apr 12, 2015 at 0:05
20
\$\begingroup\$

1962 - SNOBOL

The "StriNg Oriented and symBOlic Language". At first apparently called the Symbolic Expression Interpreter, 'SEXI', which then had to be changed to prevent the 1960-s era nerds from blushing when submitting their jobs. True story.

This was one of the first languages that could deal with strings and patterns natively. Indeed, the first version of SNOBOL had the string as its only datatype. Math was then done by parsing. The initial implementation was done on the IBM 7090. It seems to be long gone, at least, I couldn't find it. What I did find was the original paper describing it as well as a SNOBOL3 interpreter in Java, which can run on a modern computer.

The first SNOBOL had pretty much only pattern matching and basic arithmetic. SNOBOL 3 then added functions and changed the I/O, but otherwise seems to have remained backwards compatible. SNOBOL 4 changed the syntax, and from there it developed into Icon, which keeps the pattern matching but almost looks like a "normal" programming language otherwise.

The programs I have written use only functionality described in the original paper, so should work with the original SNOBOL with the exception of the I/O, which I did in SNOBOL3 style so that the Java interpreter could run them. From the paper, it seems that the difference is that SNOBOL1 uses pattern matching with a special SYS variable, whereas SNOBOL3 uses input and output variables:

  • Input:
    • 1 SYS .READ *DATA*
    • 3 DATA = SYSPPT
  • Output:
    • 1 SYS .PRINT 'A STRING' AND VARIABLES
    • 3 SYSPOT = 'A STRING' AND VARIABLES

Making these substitutions should get you 'real' SNOBOL 1. Of course, then you can't run it.

Task 1

START   SYSPOT = 'SNOBOL WAS MADE IN 1962!'

Task 2

This shows math, string handling and flow control. SNOBOL3 has useful functions, like EQ to check equality; the original SNOBOL did not, so I haven't used them.

* READ N FROM INPUT
START   SYSPOT = 'SIZE?'
        SZ = SYSPPT

* INITIALIZE
        CS = ''
        ROW = '0'

* OUTPUT PREVIOUS ROW AND START NEXT ONE
ROW     COL = '0'
        SYSPOT = CS
        CS = ''

COL     SUCC = 'N'
        EQ1 = COL
        FAIL = 'CHKE'
        EQ2 = '0'         /(EQUAL)
CHKE    FAIL = 'CHKR'
        EQ2 = SZ - '1'    /(EQUAL)
CHKR    FAIL = 'SPACE'
        EQ2 = ROW         /(EQUAL)

* CONCATENATE THE RIGHT CHARACTER TO THE CURRENT LINE         
SPACE   CS = CS ' '       /(NEXT)
N       CS = CS 'N'       /(NEXT)

* FOR NUMBERS, SUBSTRING MATCH IS ENOUGH IF IT IS KNOWN A<=B
NEXT    COL = COL + '1'
        COL SZ            /F(COL)
        ROW = ROW + '1'
        ROW SZ            /F(ROW)S(FIN)

* THERE SEEMS TO BE NO EQUALITY CHECK, JUST SUBSTRING MATCHING
* OF COURSE, EQ1 == EQ2 IFF EQ1 CONTAINS EQ2 AND VICE VERSA
* THIS ALSO ILLUSTRATES INDIRECTION
EQUAL   EQ1 EQ2           /F($FAIL)
        EQ2 EQ1           /S($SUCC)F($FAIL)

* OUTPUT THE LAST LINE
FIN     SYSPOT = CS     

Task 3

First, the boring one. The only thing of note is the smaller-than check, showing exactly how string-oriented SNOBOL really was: (B - A) '-' means "does the result of B-A contain a minus?". SNOBOL3 can also do LE(B,A), but SNOBOL 1 could not (at least the paper doesn't mention it).

* READ A AND B
START   SYSPOT = 'A?'
        A = SYSPPT
        SYSPOT = 'B?'
        B = SYSPPT

* GCD LOOP
STEP    '0' (A - B)          /S(DONE)
        (B - A) '-'          /S(AB)F(BA)
AB      A = A - B            /(STEP)
BA      B = B - A            /(STEP)
DONE    SYSPOT = 'GCD: ' A

Of course, when you have a language based entirely around strings and pattern matching, it would be a shame not to actually get to use the pattern matching and replacement. Thus, here is one of those unary-based GCDs, including routines for converting to and from unary.

* READ A AND B
START   SYSPOT = 'A?'
        A = SYSPPT
        SYSPOT = 'B?'
        B = SYSPPT

* CONVERT TO UNARY
        UNA.IN = A
        UNA.FIN = 'ADONE'          /(UNA)
ADONE   A = UNA.R
        UNA.IN = B
        UNA.FIN = 'BDONE'          /(UNA)
BDONE   B = UNA.R


* USE STRING MATCHING TO FIND GCD
STEP    '' B                       /S(GDONE)
MATCH   A B =                      /S(MATCH)
        C = B
        B = A
        A = C                      /(STEP)

* CONVERT BACK TO DECIMAL
GDONE   DEC.IN = A
        DEC.FIN = 'DONE'           /(DEC)
DONE    SYSPOT = 'GCD: ' DEC.R     /(FIN)

***************************** 
* DECIMAL TO UNARY SUBROUTINE
UNA     UNA.R =
UNA.DGT UNA.IN *.DGT/'1'* =        /F($UNA.FIN)
        .X = UNA.R
        UNA.R =
UNA.MUL .X *.Y/'1'* =              /F(UNA.ADD)
        UNA.R = UNA.R '##########' /(UNA.MUL)
UNA.ADD '1' .DGT                   /S(UNA.1)
        '2' .DGT                   /S(UNA.2)
        '3' .DGT                   /S(UNA.3)
        '4' .DGT                   /S(UNA.4)
        '5' .DGT                   /S(UNA.5)
        '6' .DGT                   /S(UNA.6)
        '7' .DGT                   /S(UNA.7)
        '8' .DGT                   /S(UNA.8)
        '9' .DGT                   /S(UNA.9)
        '0' .DGT                   /S(UNA.DGT)
UNA.1   UNA.R = UNA.R '#'          /(UNA.DGT)
UNA.2   UNA.R = UNA.R '##'         /(UNA.DGT)
UNA.3   UNA.R = UNA.R '###'        /(UNA.DGT)
UNA.4   UNA.R = UNA.R '####'       /(UNA.DGT)
UNA.5   UNA.R = UNA.R '#####'      /(UNA.DGT)
UNA.6   UNA.R = UNA.R '######'     /(UNA.DGT)
UNA.7   UNA.R = UNA.R '#######'    /(UNA.DGT)
UNA.8   UNA.R = UNA.R '########'   /(UNA.DGT)
UNA.9   UNA.R = UNA.R '#########'  /(UNA.DGT)

*****************************
* UNARY TO DECIMAL SUBROUTINE
DEC     DEC.R =
DEC.DGT '' DEC.IN                  /S($DEC.FIN)
        .X = DEC.IN
        DEC.IN =
DEC.DIV .X '##########' =          /F(DEC.ADD)
        DEC.IN = DEC.IN '#'        /(DEC.DIV)
DEC.ADD '' .X                      /S(DEC.0)
        '#' .X                     /S(DEC.1)
        '##' .X                    /S(DEC.2)
        '###' .X                   /S(DEC.3)
        '####' .X                  /S(DEC.4)
        '#####' .X                 /S(DEC.5)
        '######' .X                /S(DEC.6)
        '#######' .X               /S(DEC.7)
        '########' .X              /S(DEC.8)
        '#########' .X             /S(DEC.9)
DEC.0   DEC.R = '0' DEC.R          /(DEC.DGT)
DEC.1   DEC.R = '1' DEC.R          /(DEC.DGT)
DEC.2   DEC.R = '2' DEC.R          /(DEC.DGT)
DEC.3   DEC.R = '3' DEC.R          /(DEC.DGT)
DEC.4   DEC.R = '4' DEC.R          /(DEC.DGT)
DEC.5   DEC.R = '5' DEC.R          /(DEC.DGT)
DEC.6   DEC.R = '6' DEC.R          /(DEC.DGT)
DEC.7   DEC.R = '7' DEC.R          /(DEC.DGT)
DEC.8   DEC.R = '8' DEC.R          /(DEC.DGT)
DEC.9   DEC.R = '9' DEC.R          /(DEC.DGT)

FIN     START
\$\endgroup\$
3
  • \$\begingroup\$ Excellent background work! Not much for 1961 - it looks like COMIT is all we have.... \$\endgroup\$ Jan 21, 2016 at 9:26
  • \$\begingroup\$ @BrianTompsett-汤莱恩 Do you have a link/website to COMIT? \$\endgroup\$
    – user92069
    Mar 10, 2020 at 8:02
  • \$\begingroup\$ catb.org/esr/comit @a'_' \$\endgroup\$ Mar 10, 2020 at 8:29
19
\$\begingroup\$

2014 - Pyth

Since we have CJam, we might as well also have Pyth for completeness :)

Pyth is a golfing language by @isaacg which compiles down to Python. It's notable for being procedural and for using prefix notation. Pyth first appeared around June 2014.

"Hello, World!" Variant

"Pyth was made in 2014!

Note the lack of a closing quote, which is optional if a Pyth program ends in a string.

ASCII Art N

VQ+\Nt+P++*Nd\N*t-QNd\N

Try it online. The equivalent Python is:

Q = eval(input())
for N in range(Q):
    print("N"+((" "*N+"N"+(Q-N-1)*" ")[:-1]+"N")[1:])

Or expanded (the first and third lines are implicit):

Q = eval(input())                                        # 
for N in range(Q):                                       #   VQ
    print(                                          )    # 
          "N"+                                           #     +\N
              (                                )[1:]     #        t
                                           +"N"          #         +              \N
               (                     )[:-1]              #          P
                         +(Q-N-1)*" "                    #           +      *t-QNd
                     +"N"                                #            +   \N
                " "*N                                    #             *Nd

GCD

=GvwWQAGQ,Q%GQ)G

This program uses the Euclidean algorithm, and takes two numbers separated by a newline. Try it online.

Q = eval(input())     #
G = eval(input())     #    =Gvw
while Q != 0:         #        WQ
  G, Q = Q, G % Q     #          AGQ,Q%GQ)
print(G)              #                   G

i.uQ is even shorter if we use the builtin for GCD. This is equivalent to print(gcd(*eval(input()))) (taking two comma-separated numbers as input).

\$\endgroup\$
3
  • \$\begingroup\$ Drat - I was going to do Pyth xP \$\endgroup\$
    – minseong
    Apr 6, 2015 at 12:52
  • \$\begingroup\$ @isaacg I can't help but wonder, and might as well ask it here: was pyth inspired by pyg in any way, shape or form? \$\endgroup\$ Apr 20, 2015 at 18:37
  • \$\begingroup\$ @ɐɔıʇǝɥʇuʎs I had seen PYG before making Pyth, and it might have influenced the 1 character - 1 concept approach. However, if anything inspired Pyth it was probably golfscript. \$\endgroup\$
    – isaacg
    May 6, 2015 at 23:17
18
\$\begingroup\$

1964 - Dartmouth BASIC

BASIC is a family of general-purpose, high-level programming languages whose design philosophy emphasizes ease of use. In 1964, John G. Kemeny and Thomas E. Kurtz designed the original BASIC language at Dartmouth College in New Hampshire. They wanted to enable students in fields other than science and mathematics to use computers.

I'm looking at this manual on BASIC from 1964, and this emulator of the Darthmouth Time Sharing System it ran on. The server is still up, but sadly, registering an account seems to be impossible. For now, these programs should theoretically work:

Task 1

10 PRINT "BASIC WAS MADE IN 1964"
20 END

Task 2

10 READ N
15 FOR Y = 1 TO N STEP 1
20 FOR X = 1 TO N STEP 1
25 IF X = 1 THEN 50
30 IF X = N THEN 50
35 IF X = Y THEN 50
40 PRINT " ",
45 GO TO 55
50 PRINT "N",
55 NEXT X
60 PRINT
65 NEXT Y
70 DATA 5
75 END

Outputting something like:

N                       N
N     N                 N
N           N           N
N                 N     N
N                       N

Note how the input is typed in as part of the program (70 DATA 5); the READ instruction way at the top fetches data from there. There is no string concatenation, but section 3.1 of the manual describes how PRINT results are written to tabulated "zones" on the output.

Task 3

The slow version of Euclid's algorithm:

10 READ A, B
20 IF A = B THEN 80
30 IF A < B THEN 60
40 LET A = A - B
50 GO TO 20
60 LET B = B - A
70 GO TO 20
80 PRINT A
85 DATA 144, 250
90 END

Outputting:

2
\$\endgroup\$
1
  • \$\begingroup\$ Finally, someone did BASIC. \$\endgroup\$
    – marinus
    Aug 28, 2015 at 15:02
17
\$\begingroup\$

1991 - Python

Language History

In the late 1980s, Guido van Rossum began devising Python as a hobby. Its name comes from Monty Python's Flying Circus, a British television show of which Rossum is a fan. The first Python implementation began in 1989 and was released in 1991. It has surged in popularity over the years, becoming the language of choice for many introductory computer science courses.

"Hello, World!" Variant

print("Python was made in 1991!")

Note the parentheses around the input to print. Though this syntax works in Python 2, typically in Python 2 you would omit these parentheses. However, they're required in Python 3. As suggested by Zach Gates, parentheses are used throughout to ensure that the code presented here will work across versions.

ASCII Art N

def asciin(n):
    if n == 1:
        print("N")
    else:
        print("N" + " "*(n-2) + "N")

        for i in range(2, n):
            print("N" + " "*(i-2) + "N" + " "*(n-i-1) + "N")

        print("N" + " "*(n-2) + "N")

Functions are defined using def. String concatenation is performed using + and string repetition with *.

GCD

def gcd(a, b):
    if b == 0:
        return(a)
    else:
        return(gcd(b, a % b))

Note that Python requires structured whitespace.

\$\endgroup\$
0
17
\$\begingroup\$

1968 - Algol 68

Algol 68 was defined by the IFIP Working Group 2.1 as a successor to Algol 60.

It is an expression oriented language in which everything has a value. It is also orthogonal, in which you can use any construct in any way. This means that expressions can be on the RHS and the LHS of an assignment, for example.

All control structures have an abbreviated form as well as a long form using expressions. It also permits the definitions of operators.

The goals of the language are cited as:

The main aims and principles of design of ALGOL 68:

  • Completeness and clarity of description
  • Orthogonal design,
  • Security,
  • Efficiency
  • Static mode checking
  • Mode-independent parsing
  • Independent compilation
  • Loop optimization
  • Representations - in minimal & larger character sets

These programs have been tested with the Algol 68 Genie interpreter, which is a complete implementation of the language.

Some features that modern programmers may find different, is that empty statements are not permitted. You cannot just add ; everywhere. You have to use the SKIP statement if you want to explicitly have nothing. It also permitted the coding of concurrent programs very easily. Algol 68 also, notably, used backwards keywords as terminators, such as esac, od, fi etc.

The language had a representation used for writing the code that used many fonts representing keywords in bold, and identifiers in italic, for example. At the time, and probably still, no compiler implemented this feature of the design. The language permitted several different concrete representations of programs using stropping modes. This allowed programs to be prepared using limited character sets, such as might be found in computers in the 1960s. Consider the a short program fragment, which would be represented as:

if i < 0 then skip fi

This could be prepared for a compiler in prime stropping mode as:

'IF' I 'LT' 0 'THEN' 'SKIP' 'FI'

In dot stropping mode this would be:

.IF I .LT 0 .THEN .SKIP .FI

In case stropping mode this would be:

IF i < 0 THEN SKIP FI

I have great fondness for this language as I worked on one of the compiler implementations, as well as programming in it exclusively for many years.

Task 1

print (("Algol 68 was made in 1968!", newline))

The point to note here is the double parentheses. This is because print is a function that takes a single argument which is a variable length array of the union of all types. The inner parenthesis are the array constructor. This is how polymorphism is handled in this strongly typed language.

In case stropping mode:

print (("Algol 68 was made in 1968!", newline))


C:\>a68g HelloWorld.a68
Algol 68 was made in 1968!

Task 2

     int n;
     read ((n));
     for i from 1 to n do
          for j from 1 to n do
               ¢ here we use an abbreviated IF clause ¢
               print (( ( j = 1 OR j = i OR j = n |
                    "N"
               |
                    " "
               ) ))
          od ;
     print ((newline))
     od

In case stropping mode:

 INT n;
 read ((n));
 FOR i FROM 1 TO n DO
        FOR j FROM 1 TO n DO
            CO here we use an abbreviated IF clause CO
            print (( ( j = 1 OR j = i OR j = n |
                 "N"
            |
                 " "
            ) ))
        OD ;
        print ((newline))
    OD

C:\>a68g ASCIIart.a68
8
N      N
NN     N
N N    N
N  N   N
N   N  N
N    N N
N     NN
N      N

Task 3

     ¢ we can define our own operators in Algol 68 ¢
     op % = ( int a, b) int:
          ((b = 0 |
               a
          |
               b % (a mod b)
          ));
     int i,j;
     read((i,j));
     print(( i % j , newline))

In case stropping mode:

COMMENT we can define our own operators in Algol 68 COMMENT
OP % = ( INT a, b) INT:
    ((b = 0 |
        a
    |
       b % (a MOD b)
    ));
INT i,j;
read((i,j));
print(( i % j , newline))


C:\>a68g GCD.a68
4 12
         +4
\$\endgroup\$
5
  • 7
    \$\begingroup\$ These were probably the first Algol 68 programs I have written and executed in over 30 years. I found it so moving, that it actually brought me to tears. I never realised a "Hello World!" program could be so emotional! \$\endgroup\$ May 9, 2015 at 17:01
  • 1
    \$\begingroup\$ I was so looking forward to the Languages of the '60s and was ready with BCPL, Simula, CORAL66, Fortran 66, PL/1, SNOBOL4, POP-1 and a whole raft more, only to discover that the rules are that I have to wait 5 years of languages... A least there is a rich furrow for someone else to plough. \$\endgroup\$ May 9, 2015 at 22:43
  • \$\begingroup\$ It's really cool to see the differences between Fortran66 (utter mess of punchcard violence), APL (weird clutter of superpower-symbols), and Algol68, which is actually pretty beautiful. Today, you'd need to look into esoteric languages to find such a variety of different approaches... back then, this was rather mainstream, wasn't it? \$\endgroup\$ May 19, 2015 at 16:47
  • \$\begingroup\$ Of course, the Revised Report wasn't published until eh, 1976 was it? At least that is the copyright year that Springer gives. And the scan I found mentions 1978. \$\endgroup\$ Jul 5, 2017 at 19:59
  • \$\begingroup\$ [1] A. van Wijngaarden (ed.), B.l. Mailloux, 1.E.L. Peck, C.B.A. Koster, Report on the algorithmic language ALGOL 68, Numer. Math. 14 (1969) 79-218; also in Kibenietika 6 (1969) and 7 (1970) . [2] A. van Wijngaarden, B.l. Mailloux, 1.E.L. Peck, C.B.A. Koster, M: Sintzoff, C.B.Lindsey, L.G.L. T. Meertens and R.G. Fisker, Revised report on the algorithmic language ALGOL 68, Acta Informat. 5 (1975) parts 1-3 (reprints published by Springer, Berlin, and also as Mathematical Centre Tract 50 by the Mathematisch Centrum, Amsterdam); also in SIGPLAN Notices 12 (5) (1977) \$\endgroup\$ Jul 5, 2017 at 21:11
16
\$\begingroup\$

2010 - WTFZOMFG

WTFZOMFG is an esoteric languages based on Brainfuck. It was made by Jay Songdahl in 2010. "WTFZOMFG" is short for "What's That Function? Zen Optimized Malicious File Gophers!" .

Here is a compiler for *nix systems.

Task 1

'WTFZOMFG was made in 2010!\n"

Task 2

/&(-.N%3 >&>s-{-(-. ).N}>{-(-. ).N}_0 '\n")

Explanation:

Sorry. I'm not good at writing explanations.

/                                           # read the number and store it in cell 0
 &                                          # copy it to cell 1
  (                                         # loop while cell 0 isn't 0
   -                                        # decrease the value of cell 0
    .N                                      # print "N"
      %3                                    # copy cell 0 to cell 3
                                            # a space must be added after the number. I don't know if it's a bug of the compiler or a feature.
         >                                  # move to cell 1
          &                                 # copy cell 1 to cell 2
           >                                # move cell 2
            s                               # let cell 2 = cell 2 - cell 3
             -                              # decrease the value of cell 2
              {                             # if cell 2 isn't 0
               -                            # decrease the value of cell 2
                (-. )                       # while cell 2 isn't 0, decrease it and print " "
                     .N                     # print "N"
                       }                    # end if
                        >                   # move cell 3
                         {                  # if cell 3 isn't 0
                          -                 # decrease the value of cell 3
                           (-. )            # while cell 3 isn't 0, decrease it and print " "
                                .N          # print "N"
                                  }         # end if
                                   _0       # move to cell 0
                                      '\n"  # print a newline
                                          ) # 

Task 3

/>>/(<<&>dm<s&>>%0 <&>)<<\

Euclidean algorithm. WTFZOMFG doesn't have a command for mod, so I have to use d (divide), m (multiply) and s (subtract).

\$\endgroup\$
0
16
\$\begingroup\$

2009 - Go

Go is programming language developed by Google. The development started in 2007, but Go was announced in November 2009.

Go is a statically-typed language influenced by C which emphasizes conciseness, simplicity, and safety.

Task 1:

package main
import "fmt"

func main(){
    fmt.Println("Go was made in 2009!")
}

The first line declares the package of the code. Even a simple example as printing one line needs to be part of one package. And the executable is always called main.

Task 2:

package main

import (
        "fmt"
        "strings"
)

func main(){
    var n int
    fmt.Scan(&n)

    for i := 0; i < n; i++ {
        a := make([]string, n, n)
        for j := 0; j < n; j++ { a[j] = " " }

        a[0] = "N"
        a[i] = "N"
        a[n-1] = "N"

        s := strings.Join(a, "")
        fmt.Println(s)
    }
}

Go has a quite concise variable declaration (i := 0 is the same as var i int = 0), and the compiler determines the type. This is usually a feature more common in dynamic languages. Using this short notation it's also really easy to assign functions to variables (f := func(x int) int {/* Code */}) and create Closures.

Task 3:

package main

import "fmt"

func gcd(a, b int) int {
    for b != 0 {
        a, b = b, a%b
    }
    return a
}

func main(){
    var a, b int
    fmt.Scan(&a)
    fmt.Scan(&b)

    fmt.Println(gcd(a, b))
}

Here you can see the a, b = b, a%b syntax, which is really nice. I don't know the exact name, but in Python it's called tuple unpacking. Using the same way you can return multiple values from a function (func f() (int, string) { return 42, "Hallo"}).

Another thing happening in this code is the loop. The for loop is the only loop in Go. While-loops or do-while-loops don't exists. But you can easily create an equivalent for the while loop for condition {} or an infinite loop for {}.

\$\endgroup\$
15
\$\begingroup\$

2012 - TypeScript

TypeScript is a free and open source programming language developed and maintained by Microsoft.

Main goal is: Any browser. Any host. Any OS. Open Source. It was released on October, 2012

Hello TypeScript

Task1(name:string,year:number) {
    return name + " was made in "+ year +"!";
}

ASCII Art

Task2(n:number,separator:string,space:string) {
    var result:string = "";
    for (var k = 0; k < n; k++)
    {
        for (var j = 0; j < n; j++)
        {
            var i = ((n * k) + j) % n;
            result+=(i == 0 || i == n - 1 || i == k) ? "N" : space;
        }
        result+=separator;
    }
    return result;
}

GCD

Task3(a:number,b:number) {
    while (a != 0 && b != 0)
        {
            if (a > b)
                a %= b;
            else
                b %= a;
        }

        if (a == 0)
            return b;
        else
            return a;
}

try it online, and screencast of it.

\$\endgroup\$
2
  • 5
    \$\begingroup\$ You forgot to mention one thing: TypeScript is a superset of Javascript with few syntax changes and allows(?) strong-typed variables and arguments. \$\endgroup\$ Apr 9, 2015 at 18:27
  • 1
    \$\begingroup\$ O my god, something open source by MS! \$\endgroup\$
    – univalence
    Jul 30, 2016 at 10:24
15
\$\begingroup\$

2011 - Dart

Dart is an Open Source programming language developed by Google which is developed as a replacement for Javascript (althought it compiles to javascript). It was unveiled by Google in 2011 during the GOTO conference.

"Hello World!" Variant:

main() {
  print('Dart was made in 2011!');
}

ASCII Art N:

Bruteforce method, runs at 0(n²), but it shouldn't really matter unless you use a giant number.

asciiN(int number){
    if(number == 1){
        print('N');
    }else{
        for(var i = 1; i <= number; i++){
            String currentLine = "";
            for(var j = 1; j <= number; j++){
                if(j==1 || j == number || j == i){
                    currentLine = currentLine + "N";
                }else{
                    currentLine = currentLine + " ";
                }
            }
            print(currentLine);
        }
    }
}

GCD

simple Euclid method ported from the Snap! example above.

int gcd(int first, int second){
if(second > first){
   return gcd(second, first);
    }else{
        if(first == 0){
            return second;
        }else{
            if(second ==0){
                return first;
            }else{
                return gcd(second, first-second);
            }
        }
    }
}
\$\endgroup\$
6
  • 5
    \$\begingroup\$ I don't think that you can output a n × n ASCII art in less than O(n²). \$\endgroup\$ Apr 6, 2015 at 19:22
  • \$\begingroup\$ @PaŭloEbermann I'm not that familiar with big O notation or how to calculate complexity, but the Julia example looks like it's not O(n²). \$\endgroup\$
    – Nzall
    Apr 6, 2015 at 19:28
  • \$\begingroup\$ @AlexA. The println() function prints a string of n characters. I think that function call needs at least time O(n) to execute. In the loop, so O(n²) for the whole program. \$\endgroup\$ Apr 6, 2015 at 20:07
  • \$\begingroup\$ @AlexA. I think what Ebermann is talking about is that you have N string concatenation operations in your print function. we both do n² string concatenations in our functions. I do them once per inner loop iteration, you do them for every println(). \$\endgroup\$
    – Nzall
    Apr 6, 2015 at 20:18
  • 1
    \$\begingroup\$ If this was not ascii art it would be O(n) to display an N. (draw 3 lines to the screen, each line is O(n) therefore O(n) complexity). Or, you could say, rendering the N has O(N) complexity... hehe \$\endgroup\$
    – vero
    Apr 7, 2015 at 21:01
15
\$\begingroup\$

2007 - Clojure

Clojure is a general-purpose programming language with an emphasis on functional programming. It is a dialect of the Lisp programming language. It runs on the Java Virtual Machine, Common Language Runtime, and JavaScript engines.

You can find a online Clojure REPL at Try Clojure. It also includes a short tutorial on the basics of Clojure.

Task 1

(println "Clojure was made in 2007!")

Task 2

(defn ascii [n]
  (doseq [i (range 0 n 1)]
    (doseq [j (range 0 n 1)]
        (printf (if (or (= i j) (= j 0) (= j (dec n))) "N" " "))
    )
    (printf "\n")
  )
)

(ascii (read))

Task 3

(defn gcd [a b]
    (if (zero? b) a (recur b (mod a b)))
)
(println (gcd (read) (read)))
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Iirc, (or) can accept any number of arguments. (inc j) and (inc i) both do nothing (their return values aren't captured). I would also recommend to return the string instead of just printing it (Clojure isn't exactly meant to be procedural). Hint: (for) \$\endgroup\$
    – seequ
    Apr 10, 2015 at 18:26
  • \$\begingroup\$ @Sieg Thanks! I'm new to Clojure and am still learning. \$\endgroup\$
    – Zero Fiber
    Apr 11, 2015 at 6:04
  • 1
    \$\begingroup\$ You're not supposed to close off parentheses on separate lines in a Lisp. For instance clojuredoc refers to the Scheme style guide when it comes to formatting and indentation, and the Scheme guide calls it unacceptable: Absolutely do *not* place closing brackets on their own lines. \$\endgroup\$
    – daniero
    May 3, 2015 at 17:16
15
\$\begingroup\$

2015 - MuffinMC

MuffinMC is a Turing-complete, funny (but serious), functional and minimalist macro-language written by Franck Porcher (http://franckys.com) in mid-February 2015 out of necessity as a (quick) tool to empower a spreadsheet to be used as the only front-end controller to pilot and drive all inventory-related operations associated with a Prestashop-based merchant site for a new Tahitian fashion brand : Mutiny Tahiti (http://mutinytahiti.com -- soon to be launched).

MuffinMC is an acronym for MUtiny Functional Flexible INline Macro Command language.

To meet our requirements, MuffinMC's core features have been designed around flexible and efficient 1st-class built-in semantic constructs like iterators, lazy-evaluation, multi-functors, string-product.

MuffinMC draws its roots in (pragmatic) functional programming, FLisp and Perl. It fully supports recursivity (without any optimization), is dynamically typed and dynamically scoped (shallow-binding). It offers its users one data structure only, apart from basic data-types atoms (atoms, strings, numerals) : lists !

MuffinMC list semantics (kind of) borrows on power-set semantics, that is :

  1. All MuffinMC operation yield a list, possibly empty.
  2. Access to an any individual list element always yields a one-value-list made of that element (think of it as a singleton).
  3. The empty list is the neutral element on list operations.

To reconcile with this, the following may help :

  • One may visualize a list as the element of the list's power-set that has the greatest cardinality.
  • Visualize a list's element as the element of the list's power-set that is the singleton made of that element.
  • Visualize an empty list as the empty-set; that is, the only element of the empty-set's power-set.

As such, accessing an empty list element yields the empty-list, and not an error! Indeed, MuffinMC tries hard to throw as few errors as possible by extending that way the semantics of many traditional operations.

Task 1

#(say "MuffinMC was born in 2015 out of necessity !")

#(...) is the MuffinMC macro command for applying a function on a non-evaled argument list, here the built-in function say, borrowed from Perl.

#(say 1 2 3 ...) is functionally identical to map {say $_} (1,2,3,...)

Task 2

Define the function ascii-art() :

=(ascii-art
    '( =(*  x   #(2- $(_1))
        I   I( *($(x) " ") N)
            foo '( #(. #(I $(x))) ))
    #(say ?( #(== $(_1) 1) N "N#(map foo #(.. 1 $(_1)))N" ))
 ))

Ascii-art()'s shortest working form (88 bytes) :

=(f'(=(* x#(2-)I I(*($(x)" ")N)g'(#(.#(I$(x)))))#(say?(#(==$(_1)1)N"N#(map g#(..))N"))))
  • =(var val...) is the MuffinMC macro command to define a variable, or reassign it.

  • $(var) is the MuffinMC macro command to access a variable's value. It naturally accepts the form $(v1 v2 ...) to access many variables at once.

  • =(* var1 val1 var2 val2 ...) is the extension of MuffinMC macro command =(...) to deal with parallel assignments.

  • Variables _1, _2, ... are dynamically scoped (shallow binding mechanism) and automatically set to bind to the function's arguments. Borrowed from Perl5, system variables # (number of arguments) and @ (list of arguments) are also automatically set.

  • Functions are simply variables bound to any number of MuffinMC statements.

This interesting solution comes from combining two natural MuffinMC built-in features :

  1. The MuffinMC I(...) macro command, to define cycling-iterators, later used with the functional form #(my-iterator want-number-of-values),

  2. The MuffinMC string-product construct, an extension of the natural variable interpolation, which, given any string "F1 F2 F3...", where the Fis are either MuffinMC string literals or MuffinMC macro command (aka functional forms), will produce as many strings as given by the product cardinal(F1) x cardinal(F2) x ... .

For instance, given x a variable that holds 2 values, says a and b, and y another variable that holds 3 values, says, 1 2 3, then the evaluation of the string "x=$(x) y=$(y))" will produce 6 different values, namely, in that order :

  • "x=a y=1"
  • "x=a y=2"
  • "x=a y=3"
  • "x=b y=1"
  • "x=b y=2"
  • "x=b y=3"

This is one of MUTINY project's highly desirable features MuffinMC was designed for.

Run it !

#(ascii-art 1)

N


#(ascii-art 3)

N N  
NNN  
N N 


#(map '( #(ascii-art $(_1))) 5 7 9)

N   N
NN  N
N N N
N  NN
N   N

N     N
NN    N
N N   N
N  N  N
N   N N
N    NN
N     N

N       N
NN      N
N N     N
N  N    N
N   N   N
N    N  N
N     N N
N      NN
N       N

How does it work

Our algorithm is based on the followings:

Given a call to ascii-art(n), {n = 2p+1 | p integer, p>= 0}, the art to generate comprises n strings of n characters, amongst which, two, the leftest and rightest, are fixed and always the same : 'N'. This allows to reduce the problem in producing only the middle strings. For instance, given n=5, we would weed to produce the 5 following middle strings, each made of n-2 characters (we have replaced the space by a '_' for the sake of better visualization) :

    The 5 strings :
        _ _ _
        N _ _ 
        _ N _
        _ _ N
        _ _ _

    can be seen as resulting from splitting in groups of 3 characters
    the following infinite sequence of 4 characters :


        /---- < _ _ _ N > ----\
       |                       |
        \---------------------/    


    which, once unfolded, yields the infinite ruban : 

        _ _ _ N _ _ _ N _ _ _ N _ _ _ N _ _ _ N _ _ _ N ...
              ^     ^     ^     ^     
        _ _ _ |     |     |     |
              N _ _ |     |     | 
                    _ N _ |     |
                          _ _ N |
                                _ _ _
  • Such middle strings can easily be produced by cycling over the 4 elements sequence ('_' '_' '_' 'N') in 5 groups of 3 ; given n, the function's input, such sequence is made of n-2 characters '_', followed by the character 'N'. Cycling over this sequence requires nothing else but embedding the sequence within a MuffinMC I(sequence) built-in iterator (an iterator that cycles forever over its initial sequence of values).

  • We then simply produce the middle strings, of length n-2, by asking our iterator to give us its next n-2 values (n - 2 characters), which are concatenated together to produce the expected middle string.

  • The n middle strings are produced by repeating n times the above process, using a map to collect the n results (n strings of n-2 characters).

  • We use another powerful MuffinMC built-in construct, namely the string product, to produce the n final strings : "N#(map...)N".

  • And that's it !

    Commented script  
    
    =(ascii-art                    Define the 'ascii-art' variable to hold
                                   the function's definition.
                                   When called, its argument, the actual
                                   value of n, will be bound to the system
                                   variable _1, accessed as $( _1 ).
    
        '(                         '(...) quote macro-command -- protects 
                                   its arguments, here the function 
                                   definition, from being evaluated.
                                   We want to keep it literally for further evaluation.
    
           =(*                     =(*...) // assignment macro-command.
                                   Similar to the Lisp (let (...)...),
                                   not the let* !
    
               x #(2- $(_1))       Define the variable x to hold the value 
                                   n-2.   
    
               I I(                Define I to be an iterator over the 
                                   the x+1 characters sequence :
                    *( $(x) " ")   . x white-space characters
                    N              . 1 'N' character (here the atom N)
                 )
    
               foo '(              Define the variable foo as a function 
                      #(.          to catenate ( #(. s1...) )
                         #(I $(x)) the iterator's next x elements.
                       )            
               )
           )                       End of =(*...
    
        #(say                      Print each element of:
           ?(                      If
              #(== $(_1) 1)        n equals 1
      N                    the atom N,
      "N#(map foo #(.. 1 $(_1)))N" else the n strings as a string-product 
                                   resulting from foo-computing the  
           )                       n middle-strings.
         )
     ))
    

Task 3

Define the function gcd() :

=(gcd '( ?( #(== $(_2) 0)
        $(_1)
            #(self $(_2) #(mod $(_1) $(_2)))) ))

gcd()'s real shortest form (37 bytes - 2bytes gain thanks to Rodolvertice)

=(g'(?(#(z$(_2))$(_1)#(g$(_2)#(mod)))))

Run it !

#(gcd 225 81)

yields 9.

That's it.

Thank you for the nice game, and possibly for your interest. The language is available to any one who would like to play with, use it, or even extend it. Just ask for it and I will be glad to send it in.

Cheers

Franck


PS. MuffinMC's current implementation is in Perl5. The source code is about 2000 lines of modern Perl, including comments, and it comes bundled with a non-regression test-suite, which is great to learn hands-on MuffinMC constructs and semantics.

\$\endgroup\$
3
  • \$\begingroup\$ Really nice! The shortest form of the ascii-art has a shortened function name, but the GCD shortest doesn't. Is this intentional, because if it isn't you can shave off another 2 bytes. +1 \$\endgroup\$
    – vero
    Apr 10, 2015 at 8:21
  • \$\begingroup\$ Sure, and it's intentional. Should I ? yes, let's do it ;) Thanks for the post, and your appreciation. \$\endgroup\$ Apr 10, 2015 at 10:18
  • 1
    \$\begingroup\$ Since you're trying to get rid of extra characters (and because I can be an incorrigible grammar-nasty), you could (should) remove the space in front of the exclamation mark for the first task. That space is correct in French afaik, but not in English. \$\endgroup\$ May 5, 2015 at 6:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.