
Ko – A concurrent, immutable, functional language - petar
https://github.com/kocircuit/kocircuit
======
yiyus
There is not a single example in the README. I checked the step-by-step guide,
but it starts with installation and documentation instructions, then imports,
and I don't know yet how the language feels like. Ok, let's check that
handbook then. Computation model, type system, ...

Please, I just want to see a program with a dozen lines of code to see what it
looks like. Of course, more extended examples with the intended usage would
also be very welcomed.

I eventually found this:
[https://github.com/kocircuit/kocircuit/blob/master/lessons/e...](https://github.com/kocircuit/kocircuit/blob/master/lessons/examples/helloworld.ko)
but I think it should be much easier to arrive there.

~~~
giancarlostoro
The law for making a new language: always include examples up front.

~~~
erwan
For anything _you want other people to use_ really

------
ivoras
I can't be the only one who's annoyed by language writers introducing
arbitrary uncommon syntax apparently just for the sake of doing something new?

Lua's great little language but writing ~= instead of != is simply annoying.
In this "Ko" language, it looks like they do returns with a colon, as in
"return: x" \-- why??? I won't even go into Rust picking up Perl's bad habit
of looking like line noise with all the ASCII sigil usage in advanced code.

Also, any language which doesn't have a "hello world" example in its front
page is doomed. Even such a wide-spread language as Python has code snippets
practically first thing on its web page! This is not by accident!

~~~
alan-crowe
I wonder why they preferred ~= over =/= ?

I would sympathize with using =/= for "not equal" because it is ASCII art for
the traditional mathematical notation of using an equal sign with a line
through it. Though it might be better just to permit carefully selected
unicode characters such as
[https://www.fileformat.info/info/unicode/char/2260/index.htm](https://www.fileformat.info/info/unicode/char/2260/index.htm)

=/= is disappointing as art because it is too wide, but it has obvious
mnemonic power.

Would you object to =/= as "arbitrary uncommon syntax" because it is poor art?
Does its mnemonic power save it from the criticism of being "new for the sake
of new"

~~~
fanf2
MATLAB also uses ~= but I am not certain that is where Lua got it from. (The
paper on the history of Lua does not say...)

------
tombert
I don't want to be "that guy", but a small sample in the README would be nice.
Tough to tell if I'll like a language if I can't even see it without
traversing through the docs.

------
choeger
But what's its type discipline? H/M polymorphism? Overloading? Subtyping?

How is it evaluating? Eager? Lazy?

What values are supported? Records? What flavor? Modules?

~~~
rhencke
You may find the Ko Handbook useful, as much of this is addressed there:

[https://kocircuit.github.io/language/](https://kocircuit.github.io/language/)

------
kyleperik
I love the generic function aspect of this, where there aren't necessarily
specific inputs or outputs. This will make code reusable by factors. A simple
use being not needing to define both `toRadians` and `toDegrees`, just
definite the relationship. But I believe this can be taken to the point of
getting backpropagation for free once forward propagation is defined in neural
networks.

Not to steal any thunder, but I've been prototyping a language very built on
this idea.

[https://git.kyleperik.com/kyle/judo](https://git.kyleperik.com/kyle/judo)

~~~
theoh
I could be jumping to an incorrect conclusion, but I think you are misreading
the description of Ko's genericity. It doesn't mean that inputs and outputs
are not distinguished. It just means that arguments and return values aren't
explicitly typed. The kind of Prolog-style unification you are talking about
is something different.

~~~
kyleperik
You're right. This sentence and the general syntax of the language mislead me

> Genericity means that functions do not have to declare argument and return
> value types, which makes them highly reusable.

Thanks for being kind about pointing out my massive presupposition

------
vmchale
Is this a research language? I don't understand how this offers anything
beyond what already exists.

I'm also suspicious of the fact that it's implemented in Go. I would think
that someone who knew functional programming well enough to create a new
language would implement the language in Haskell or OCaml or even Standard ML.

Also the type system looks pretty bad. No algebraic data types.

~~~
Blackthorn
What a bizarre criticism. Most of the newer popular functional languages
aren't implemented in those, but rather Java, and for the same reason given in
the readme for Go.

~~~
haggy
> Most of the newer popular functional languages aren't implemented in those,
> but rather Java

Well, that's not entirely correct. I assume you mean they run on the JVM?
Language like scala are actually written IN scala. The only thing that is in
java is the interpreter but the entire compiler is scala.

~~~
Blackthorn
True enough for Scala, but Clojure has plenty of Java code.

~~~
phyrex
OTOH clojure script is completely written in clojurescript

------
samatman
I just want to say that "Ko" is an excellent name for a deadlock-free language
written in Go. Kudos.

~~~
iainmerrick
Ha! I didn’t even notice, thanks for the hint.

------
thosakwe
Found the examples:
[https://github.com/kocircuit/kocircuit/tree/master/lessons/e...](https://github.com/kocircuit/kocircuit/tree/master/lessons/examples)

------
weberc2
This is interesting. I see it has an interpreter, but it's unclear at a glance
whether "interpreted" is the default production mode of the language or if the
interpreter is available to facilitate a repl or smething.

Skimming some of the .ko files, I like that it seems readable and familiar
(even if there are some oddities). No matter how much time I spend with
Haskell and OCaml, I always spend conscious effort trying to mentally parse
the source code.

------
notduncansmith
This reminds me a lot of a library I wrote called Factfold
([https://github.com/notduncansmith/factfold](https://github.com/notduncansmith/factfold)).

Something I noticed while working on it is that the declarative style is not
always the most comfortable way to describe things, and well-written
imperative code is declarative in its own way. Somewhere in most useful
programs, it helps to have the imperative escape hatch until you can support
the best declarative expression.

------
heavenlyhash
Interesting.

Random observations in no particular order:

\- The simple assignment syntax _looks_ somewhat procedural and is easy to
read in small hunks at a time, but is still functional. I like this. This
meshes well with the very real limits of how the human brain can parse things.

\- I wish there were type declarations. There's a type system, but it seems to
be _all_ inference. Type declarations just at the function inputs and outputs
(and leaving it pure inference in the middle) would promote readability when
you've got no compiler in hand and are just eyeballing the pure text, in my
opinion.

\- I'm surprised by the inclusion of a system of nonlocal returns
(panic/recover). It still looks _relatively_ functional, but A) boy that's not
an area where the word "relatively" is comfortable to use and B) I shudder to
think what the inferred types will tend to explode into when using this
feature (an Either of an Either of an Either of a ...?) in a nontrivial
program (and the examples don't really shed light on that either, due to the
"all inference" model leaving us with no plain text declarations of types in
sight).

\- I haven't seen any examples yet of what happens and how you're supposed to
resolve it when the type inference can't quite figure it out. There seem to be
some examples of doing explicit casts which seems to be a workaround for this,
but I don't see it discussed very clearly.

\- The quick and easy syntax for returning new record/structure types seems
nice. Though I'm again a tad worried that the range of types I could end up
producing would get pretty large.

\- The syntax holistically seems to keep things from "drifting to the right",
which seems to be a common readability cramp that emerges in many functional
languages. Nice.

\- Using the term "Variety" for roughly "closure" is... very nonobvious to me.
But I shouldn't nitpick on terminology. (And for what it's worth, I read the
protobuf that Ko uses internally to define its types of types before anything
else, and so maybe I'd be less surprised if I had encountered it from from the
docs and lessons first.)

Caveat: these are all "hot takes" from the couple dozen minutes of digging
I've done so far. I might be reading some things wrong or have missed some
documentation, so take these comments with a grain of salt and do your own
looking as well.

Overall, this seems neat, but simultaneously leaves me a little worried that
I'd be able to too easily write things in which the type inference finds
something that compiles, but isn't the type that I would've declared.

I'd be really interested to see what this shapes up like if combined with some
system for explicit type declaration. Gluing Ko together with a serial data
schema like Protobuf and using Ko for "migrations" seems like it could be a
really useful combination, for example.

~~~
nine_k
Yes, type declarations are _documentation_ , and tell me about as much, or
more, about a function than its name, when reading e.g. Haskell code. They are
a necessary usability feature.

------
minionslave
Would it be possible to have a small hello world example in the README?

------
simcop2387
Couldn't find it easily, but what model are they using to make this dead-lock
free as they advertise? I've seen a number of languages try to accomplish this
same goal but usually with a huge caveat on what kinds of programs are
allowed, or by randomly killing threads when a dead-lock is detected.

~~~
Syzygies
If you understand why a purely functional language like Haskell rocks at
parallelism without worrying about deadlocks, then: same answer here.

I'll agree this isn't ready yet to be the first example of functional
parallelism in someone's life, but I'm pretty excited to play with this
computational model.

~~~
simcop2387
Even with Haskell you can still have deadlocks [1]. They give you the tools to
write code that you can prove won't have them, but restricting the kinds of
programs you can write. But it's an opt-in thing, it's not a promise of the
language that you can't do it. Rust is trying to do a similar thing, but it's
still also possible to write yourself into a corner with deadlocks if you work
against the feature.

Another language I saw recently that has this promise was Pony which uses an
actor and message passing model to try to accomplish this but it doesn't
actually prevent you from hitting the case, instead it'll just kill a random
actor until the deadlock is gone [2]. This can work but it needs to be up
front that you MUST write your software to be ready to be killed at any time
and continue to function.

It's really an impossible situation to completely "solve", given that doing so
would require a solution to the halting problem. So it's always a fun place
for me to start looking at any new language if they talk about locks and dead-
locks. So far I think Haskell and Rust (and probably other ML family) have the
best balance being struck since you can opt in to statically proving this if
you restrict those parts of your program but you're not required to do so by
the language itself.

[1] [https://www.fpcomplete.com/blog/2018/05/pinpointing-
deadlock...](https://www.fpcomplete.com/blog/2018/05/pinpointing-deadlocks-in-
haskell) [2]
[https://news.ycombinator.com/item?id=9485333](https://news.ycombinator.com/item?id=9485333)

------
jerf
Hot takes, as someone else says:

[https://github.com/kocircuit/kocircuit/blob/master/lessons/1...](https://github.com/kocircuit/kocircuit/blob/master/lessons/1-basics/1-files-
packages-imports.md) : You might want to consider using Go syntax whenever it
is not a problem. 'import "package" as foo' rather than 'import foo "package"'
is just pointless change, unless there's more to the "as" statement later.

[https://github.com/kocircuit/kocircuit/blob/master/lessons/1...](https://github.com/kocircuit/kocircuit/blob/master/lessons/1-basics/3-arguments.md)
: Whoa, I have to type the name of all the arguments I want to use to every
function on every invocation? That's a level of noise I'm not interested in.
In
[https://github.com/kocircuit/kocircuit/blob/master/lessons/1...](https://github.com/kocircuit/kocircuit/blob/master/lessons/1-basics/4-default-
arguments.md) it is claimed this is necessary to support default arguments,
but see Python's function argument invocations. (And be sure you see _all_ of
it; for instance, it is little known that you can:

    
    
        >>> def f(x):
        ...     return x * 2
        ... 
        >>> f(x = 2)
        4
    

that is, even a positional parameter can be passed by name if you insist.)

Coming back after reading on, I see you let Eq and Sum and such get by without
argument names. Generally a language should not reserve privileges for itself
that it does not grant to its users without a really good reason.

[https://github.com/kocircuit/kocircuit/blob/master/lessons/1...](https://github.com/kocircuit/kocircuit/blob/master/lessons/1-basics/4-default-
arguments.md) : I literally have no idea how you are using the word "monadic"
in this section; it is neither the proper mathematical term, nor the very
close Haskell term, nor any subsequent misunderstanding I've ever seen of the
Haskell term ported into other languages, nor can I particularly connect it to
the philosophical meaning, nor do I (glancing ahead) see any other
documentation for it. My search was not exhaustive, but taking such liberties
with a term like that sets off a lot of flags for me.

[https://github.com/kocircuit/kocircuit/blob/master/lessons/1...](https://github.com/kocircuit/kocircuit/blob/master/lessons/1-basics/5-intermediate-
steps.md) : This is, IMHO, a rather dirty hack around trying to copy the way
pure Haskell code can implement definitions without much concern for order,
while at the same time having side effects in the code. That "DoubleGreeting"
on the bottom is getting really ugly (and I mean in terms of the semantics of
what is being represented there, not the surface syntax layer), and it's still
in the sample code, where things should be looking artifically fake-pretty
because the real-world hasn't intruded yet. It's a solution to a problem that
shouldn't have been introduced in the first place.

[https://github.com/kocircuit/kocircuit/blob/master/lessons/3...](https://github.com/kocircuit/kocircuit/blob/master/lessons/3-types-
and-values/6-structures.md) : I expect "repeated assignment" will be difficult
to follow with nested structures. Also, what happens if I move yearOfBirth
below the repeated "occupations"? My point here is not that there isn't an
answer; it's that I can come up with 3 or 4, which is the real problem.

[https://github.com/kocircuit/kocircuit/blob/master/lessons/3...](https://github.com/kocircuit/kocircuit/blob/master/lessons/3-types-
and-values/7-varieties.md) : Variety is a bad name for this concept. It's too
close to the well-defined "variant" term and causes serious concept clash in
my head. "Function object" or something, maybe. "Closure" might work, haven't
studied it closely enough to be sure.

[https://github.com/kocircuit/kocircuit/blob/master/lessons/3...](https://github.com/kocircuit/kocircuit/blob/master/lessons/3-types-
and-values/7-varieties.md) : This appears to mean that the "null" value is
forced into all types, which makes this, surprisingly, even worse than Go
itself on this front, which at least has a few types of values that can't be
null.

[https://github.com/kocircuit/kocircuit/blob/master/lessons/3...](https://github.com/kocircuit/kocircuit/blob/master/lessons/3-types-
and-values/9-equality-and-hashing.md) : At scale, you can't provide a generic
hashing function. It's appealing, but it really can't be done. At best you can
provide an interface. Don't even provide a default implementation. Java has
had a long history of problems with that.

General comment: Using the functions for flow control is OK, but combining
that with arbitrarily-reorderable function argument parameters is crazy.
Anyone who writes If(else: ..., when: ..., then: ...) is just insane anyhow,
so don't even allow it in the syntax/grammar, because it _will_ happen. It
seems to me you basically have an imperative language trying to look
functional, while I see little to nothing "functional" about it, and you'd be
better off just being an imperative language and take advantage of structured
programming's implicit control flow <-> source code layout correspondence.
You're paying the price for some things you're not successfully taking
advantage of.

[https://github.com/kocircuit/kocircuit/blob/master/lessons/5...](https://github.com/kocircuit/kocircuit/blob/master/lessons/5-debugging-
and-logging/1-logging-with-show.md) : Re: arg0, arg1, arg2, etc., another
solution to a problem that should simply have not been introduced.

My summation is that even in the examples, I'm seeing a lot of little quibbles
stack up and become some big problems, and that's before I'm trying to
actually code in this. I'd suggest some more thinking about the language's
goals, and ensuring that every feature is in harmony with that goal and
everything not necessary for it has been cut, because that is not where this
language is right now.

------
Eli_P
What's the main advantage of Ko over Go and Pony[1]? I never coded in any of
them, but looks interesting.

[1] [https://www.ponylang.io/discover/](https://www.ponylang.io/discover/)

------
pier25
Is this like Haxe?

------
jackhalford
.ko is already used for kernel objects :(

~~~
chrisseaton
Many file extensions are in multiple use. There's only so many two or three
letter permutations.

~~~
timbit42
File extensions aren't limited to 3 characters these days.

------
pulsarpietro
Y.A.U.L.

------
hota_mazi
"Active development" but the last commit was two months ago...

