
An Opinionated Treatise on Cosmos, a New Programming Language - mccosmos
https://medium.com/@McCosmos/a-treatise-on-cosmos-the-new-programming-language-905be69eb4af
======
norswap
It looks like Oz [1] declarative variables could help implement a lot of this
stuff. Essentially, its variables are pointers that can be assigned to only
once. As such you can pass an unbound variable to a function and have it bound
to produce a result.

You can also do "unification" between two variables, meaning that it will try
to make the two variables equal to each other. Typically, one or both of the
two variables hold a partial data structure - a data structure that references
unbound variables - and it will binds some of these variables to make the
unified variables compatible, if possible.

[1]
[http://en.wikipedia.org/wiki/Oz_%28programming_language%29](http://en.wikipedia.org/wiki/Oz_%28programming_language%29)

~~~
aplummer
I was also lost at functor...

~~~
norswap
Which is not mentioned in my comment or in the wikipedia page :)

But I get your point. Oz is a nice language which suffers from poor marketing
and lack of support. It's a really lovely language though. It's the closest
take I've seen so far of enabling expressibility by using a small number of
orthogonal primitives. That's basically all the "multi-paradigm" talk is
about.

If someone is interested to seriously hack on Oz, I think Peter Van Roy [1]
would be interested, esp. if you can pitch it as a research project somehow
(easier to get funding). I can make introductions if necessary.

[1]
[http://www.info.ucl.ac.be/~pvr/cvvanroy.html](http://www.info.ucl.ac.be/~pvr/cvvanroy.html)

------
skrebbel
This is a genius writeup. My earlier limited experience with logic programming
resulted in lots of confusion and "what's the use?". Because of this, I would
probably have me not even click the link if the word "logic" had been in the
title (and I suspect I'm not alone in that).

Instead, the author starts with the familiar concepts and very gradually and
comfortably flows into logic programming concepts, making me go "hey! that's
handy!". That's a feeling I've never had with logic programming before, and I
didn't even give Cosmos a try yet.

Hats off! I'm definitely going to play around with this.

------
mccosmos
Thanks for the replies. A few comments:

1\. I might have gotten a bit carried away when writing some parts of the
article.

2\. "Functors" are the same as functors from Prolog. Note that Prolog lists
are functors too. They also may enable the language to have an 'Option' type
like in some functional languages.

~~~
skrebbel
1\. Please keep getting carried away

2\. I completely didn't understand how a functor can make a list. Note, to me,
a functor is a C++ class that overrides operator(). I loved how your writeup
allowed me to understand Cosmos concepts _without_ learning Prolog, so an
introduction to functors (maybe a later blog post?) would be warmly
appreciated :-)

~~~
tempodox
Yes, C++ is notorious for abusing the “functor” concept in the way you
mention. Compare the Wikipedia article:
[http://en.wikipedia.org/wiki/Functor](http://en.wikipedia.org/wiki/Functor)

A better way to describe a class that defines the »operator apply« is
“function object”, as it is called in Lisp.

------
timClicks
It's really neat that someone is trying to make logic programming accessible,
but the introduction and the first fews sections are really offputting. There
are lots of highly performant new languages competing for attention, and
statements like "Today I want to talk about programming. It is interesting to
note that I have solved it. Yes, I solved it." will drive a lot of the
potential audience away.

I recommend breaking this into two posts. One's a highly readable introduction
to a new language (e.g. this post's 2nd half). The other's the author's
opinions about the state of programming languages (1st half).

Well done for the technical work behind this project and the bravery for doing
something about fixing problems you find in the world.

~~~
mbrubeck
The Readme file at
[https://github.com/mcsoto/cosmos](https://github.com/mcsoto/cosmos) is a nice
concise introduction to the language. The blog post is more of a manifesto.

~~~
timClicks
Ah right.. I read the post in isolation. Thanks for the reference.

------
skrebbel
I was confused by this example:

    
    
        rel p(s, x)
         if(s = ‘a’) //this is sugar for [(s=’a’ and x=0) or x=2]
          x = 0
         else
          x = 2
    

Why does it transform to

    
    
         [(s=’a’ and x=0) or x=2]
    

and not

    
    
         [(s=’a’ and x=0) or (s!=’a’ and x=2)]
    

(or whatever "not equals" is in Cosmos)?

In any language I know, "else" means "do this when the guard was _not_ true",
and not "nondeterministically maybe do this other thing instead, if you want".
Did I simply misunderstand it? (note that I got lost at the "soft cut" part,
but did I get it right that "choose ... else" is closer to what I'd expect "if
.. else" to do?)

Given that accessibility to people used to imperative languages is a core
goal, I'm not sure that the choice of making "else" mean "yeah whatever" is
the best one. Maybe it's better to replace it by a different keyword entirely
("if.. or.." maybe). On a related note, just in case you're not familiar with
it, I believe that maybe the "if.. fi" construct in Dijkstra's Guarded Command
Language[0] is an easy way to get imperative-thinking people to embrace
nondeterminism. It feels a lot like normal imperative "if", except there is no
"else". If you want "else", you need to add another guard explicitly, with the
negation of your first guard. This way, it's easy for people to grasp that the
order of the guarded commands have no meaning. It also makes introducing
nondeterminism very explicit.

[0]
[http://en.wikipedia.org/wiki/Guarded_Command_Language#Select...](http://en.wikipedia.org/wiki/Guarded_Command_Language#Selection:_if)

~~~
vidarh
You're thinking imperatively. It is not "do this" but "generate the set of
possible solutions".

The "soft cut" part I'm presuming is similar to Prolog, where a "cut"
indicates that once you've gotten past it, you can't backtrack (roughly - my
knowledge of Prolog is rather limited) to try other arms - so "choose" is
forced down one path by the guard, and then not allowed to also evaluate the
other arm, while "if" can generate both alternatives.

~~~
ajuc
I am somewhat familiar with declarative programming and Prolog and still don't
get it.

The problem is there even without else.

    
    
        if (s='a')
            x=2
    

Should it be

    
    
        (s='a') and (x=2)
    

or

    
    
        ((s='a') and (x=2)) or (s!='a')
    

Because IMHO it should be the second one (it's also basicaly the logical
definition of implication, which IMHO should be consistent with "if").

The first interpretation of if without else just give you another way of
writing:

    
    
        s='a'
        x=2
    

so why "if" at all?

And if we take the second interpretation of if without else, then when there's
else - it should also get the !if_condition implicitly.

~~~
mattcwilson
"if" here isn't a perfect analog to a traditional imperative language's if
statement.

A better set of keywords to describe the logic might be "when ... allow".
Because there is an implication here, it's just in reverse.

Because the relation finds all possible solutions that meet the relationship,
this code really reads "when s is the letter a, allow x to be 0, and call that
a solution. Otherwise, any pairing where x is 2 is a solution."

So if you were to call p(s, 0), you would find that you only get one solution,
where s must be 'a'. From an imperative-ish POV, that "sets" (constrains) s to
'a'.

OP is using if, _combined with the notions that you take only the first of all
relation solutions, and that you treat the rightmost relation member as an
output_ , to achieve an imperative-like behavior in a non-deterministic logic
language. Which is mentioned in the paragraph following the example.

------
randallsquared
> If you only have a single feature then you only need to learn one thing and
> it can only go wrong one way.

I beg to differ. You can definitely go wrong in more ways with Lua tables
_because_ they stand in for modules, arrays, and maps.

~~~
fit2rule
Well, I've been writing Lua code for a few years now and I think that the ways
you can go right with Table usage far outweigh any liabilities that newcomers
to the language will suffer as they learn to do powerful things with the
simple features. As long as you know what modules, arrays, or maps are, and
what uses they can provide, then you can't really screw things up too much
with the Lua table. But of course, that's expecting a lot from a modern
language user ..

~~~
randallsquared
I don't disagree with any of that. I just think that combining concepts
doesn't necessarily reduce the number of ways things can go wrong (even if, as
you say, it increases the number of things that can go right as well).

For an extreme case of what I mean, consider Church numerals.

~~~
fit2rule
Well, tables can and do often "go wrong", but alas the success-case is rarely
accounted.

I would warrant that there must be something to them, or else we wouldn't be
discussing them as persistent features of a social phenomenon, which is
something I think we all take for granted about software language: it is
entirely social.

Whereas your extreme case is mathematically derived, our social habits occur
because of decisions.

------
sergiosgc

        l = [1, 2]
        l = Cons(1, Cons(2, Cons))
    

Ah, my other car is a cdr. I almost longed for my lisp (scheme) days.

I quickly recovered, though..

~~~
Guthur
Sorry you are mistaken, your CARs are numbers.

Your other CDR contains Cons. Which may just be a function.

~~~
gmfawcett
"My other car is a cdr" is an old joke. It is a play upon a kind of humourous
bumper sticker ("my other car is a Ferrari") which was popular at one time.

------
chuckcode
Does Cosmos have any characteristics that would allow easy JIT speed
optimizations? I would love to see language design go green by allowing easy
optimizations that help us save both our valuable electricity and our time.

Are there design patterns that would allow us to more easily enable JIT for
performance or even multithreading or GPU usage? V8, FTL and SpiderMonkey have
all significantly sped up javascript performance making for much more
efficient execution and better user experience. Python and PHP seem harder to
adapt to JIT compilers as Facebook keeps working on HHVM for PHP and JITs for
Python like PyPy lots of compatibility issues with existing libraries.

p.s. I for one really appreciate the entertainment value of exaggerated and
opinionated style as long as the author realizes it is partly for
entertainment, calls it out in the title and clearly isn't taking themselves
too seriously. I already read enough serious and earnest tech articles...

------
iamdanfox
The idea of declaring a variable to represent a bunch of different values
seems refreshingly different to so many popular languages today.

I'd love to see a few real world applications written in idiomatic Cosmos!

------
kirsebaer
Why do so many programming languages have common words or single letters as
names? Doesn't that make it difficult to search for discussions on these
languages? Why not Kozmoz instead of Cosmos?

------
jblow
It is cute, but you can't design a language for toy problems or you run into
problems with bigger software.

I kind of stopped reading here:

"Since it is declarative code, update returns a new world w2 instead of merely
modifying w1. The funny thing is, just by doing this our code becomes 200%
better. For example, you can now modify the code to store all world states in
a list!"

Uh huh. Try doing that with a nontrivial game that needs to be performant, and
let me know how that works out.

~~~
jblow
I should clarify before people respond antagonistically ... as someone who is
designing a programming language, I think it's great any time someone is
making languages and trying out new ideas. That part is great, if you want to
make a functional imperative declarative loosely strongly typed language then
hey, go for it.

But I think one has a responsibility not to try and sell one's project as
something it's not, which especially means being careful with claims. I know
this is sometimes hard because a lot of language design stuff comes from the
academic community which notoriously overclaims (because it is their job to
overclaim), and it is easy for that culture to rub off.

But if you are going to say something like "just by doing this our code
becomes 200% better", with a straight face, about something that most
practitioners know is going to be terrible in most cases without a tremendous
amount of additional work and solving of unsolved problems (solution not
shown), you're just telling the reader that they can't take you seriously.
It's a bad thing to do.

~~~
corysama
> But if you are going to say something like "just by doing this our code
> becomes 200% better", with a straight face

I think this is something a lot of people here are having a hard time with:
The article is not being said with a straight face. The unsolved problem of
elegant I'm-holding-back-a-funny-face font technology has confounded the
Internet for forty five years and still counting.

------
username3720
A fun paper, but it neglected to explain its means of modularization. I had to
read the language implementation to discover the 'require' keyword used to
import functions.

Projects like Mercury ([http://mercurylang.org/](http://mercurylang.org/)) are
also covering similar space.

~~~
abathologist
Michael Hendrix described Mercury as Haskell + Prolog, which is accurate, I
think, and an indication that Mercury is pretty far removed from what Cosmos
is trying to do. (I'm more interested in Mercury). Cosmos looks like it wants
to be a multi-paradigm scripting language, whereas Mercury is aiming for
logical purity (no cuts), strong and static typing, and high speed (...for a
Prolog). I think Picat ([http://www.picat-lang.org/](http://www.picat-
lang.org/)) or Ciao ([http://ciao-lang.org/](http://ciao-lang.org/)) are
probably closer matches to Cosmos.

~~~
abathologist
Sucks, cannot edit old comment. Correction:

Michael Hendrick:
[https://www.youtube.com/watch?v=G_eYTctGZw8](https://www.youtube.com/watch?v=G_eYTctGZw8)

------
zeeh
Am I correct in saying that Cosmos is both Turing complete and incomplete? In
addition, in the world splitting example, does this result in a fork or exec?

------
jhrobert
I wrote quite a lot of TurboProlog code for a while some 25 years ago. I
always wondered why there were no syntax sugar for nested 'or' Horn clauses.

Now it's fixed. Cool. So is the rest of Cosmos syntax sugar, cool, kudos.

I guess some OO would be a nice addition. And, that's the thing of the day: an
efficient JS transpiler and a decent IDE with a stepping debugger. That's
asking a lot. I know.

------
fspeech
Prolog is neat. There is probably a Prolog embedded in some of the C++ type
checkers. The problem is that the world at large is often in a flux and can't
be conveniently described in terms of static relationships, which makes Prolog
programming at large challenging to do (or you augment Prolog with features
that make it more or less imperative).

~~~
JadeNB
> The problem is that the world at large is often in a flux and can't be
> conveniently described in terms of static relationships

Apparently there was work in the late '90's on accounting for this without
`assert` / `retract`-style messiness:
[https://en.wikipedia.org/wiki/Transaction_logic](https://en.wikipedia.org/wiki/Transaction_logic).

------
al2o3cr
Any article that intends to explain why logic programming is the One True Way
without covering "how to prevent super-exponential backtracking from eating
your face" is missing an important part.

------
yawaramin
So, you came out pretty strongly for strong typing. But you didn't include
anything about creating new types. Did you not want to focus on that in this
article or...?

------
n2820
Is it just me or does this resemble visual prolog quite a bit? Though the
syntax of Cosmos seems nicer, it seems as if most of the ideas are implemented
in visual prolog.

------
wyager
If your justification for creating a new language is "I made snake in a bunch
of different languages!", I am extremely skeptical.

And, as is often the case, it is impossible to have a universally beneficial
compromise in programming language features. There are some things you simply
_cannot have_ if you don't lean strongly one way or the other, and you end up
with a mediocre in-between with none of the benefits of either extreme. Case
in point: type systems and the ability to compile to tight native machine
code. In a dynamically typed/untyped language, you need to have multiple
layers of indirection.

------
tel
I wonder why they're called functors.

~~~
mjn
It's a pretty overloaded term. I haven't looked into the Cosmos semantics
much, but since it's mentioned in the "logic programming" part of the
language, I suspect it's referencing the Prolog sense of the term:
[http://www.cse.unsw.edu.au/~billw/prologdict.html#functor](http://www.cse.unsw.edu.au/~billw/prologdict.html#functor)

~~~
Chinjut
I believe this terminology goes back to Rudolf Carnap; it actually predates
the use of "functor" in category theory.

------
devhinton
This is a good writeup but I have to say:

"We really can do anything. The sky is not the limit in Cosmos. We can go
beyond into outer space."

*pukes

Good article so far, but that line smh

------
digguser
A new programming language a day keeps the doctor away.

~~~
bigtunacan
So true. I thought Spider Programming was the current best language ever, but
apparently that is so 9 hours ago...

------
striking
So I think that there are a lot of good ideas in here. Unfortunately, since
I've never seen an application written in your language, I have no idea
whether it's good or not.

Lemme tell you about TI-BASIC (for the TI-84). That stuff was the bee's knees.
One day I wrote a really slow loop to translate whatever key was pressed into
a number if the key corresponded to a button on the number pad. [1]

In JS the loop would look like

    
    
      var output = -1,
        codes = [103,92,93,94,82,83,84,72,73,74],
        pressed = getKey();
      for(var i=0;i<codes.length;++i)
        if(codes[i]==pressed){
          output = i;
          break;
        }
    

Way too complicated, way too slow for an interpreted game program on a 6MHz
Z80. But TI-BASIC had some cool higher-order functions! It didn't even have to
be a loop at that point, check out how succinct it became:

    
    
      var codes = [103,92,93,94,82,83,84,72,73,74],
        pressed = getKey(),
        digits = [0,1,2,3,4,5,6,7,8,9];
    
      var output = sum((codes == pressed)*digits);
    

(Yes, this isn't "really TI-BASIC" but that stuff is a pain to type on a
computer. Sorry.)

How? `codes` is an array, which, when tested against a scalar, produces an
array of 0 or 1 to indicate false or true. These, multiplied by digits,
produce an array of 0 and a number that is pressed. The summation gets that
number because adding by 0 just returns the number. (Also, getKey can't return
more than one key at a time.) And because the loop happened inside the
operators, the loop was run in assembly, which made it about 30x faster.

This is why I believe that TI-BASIC is the best programming language. (I
don't, really. But I'm more believeable than the unexplained Functor malarkey
and how it can somehow put me into _outer space_ ;)

[1]: [http://tibasicdev.wikidot.com/key-
codes](http://tibasicdev.wikidot.com/key-codes)

~~~
aidenn0
Did you read the TFA? It linked to the cosmos implementation, along with the
information that it was implemented in cosmos.

Here's one file from it:

[https://github.com/mcsoto/cosmos/blob/master/src/cosmos.cosm...](https://github.com/mcsoto/cosmos/blob/master/src/cosmos.cosmos)

