Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Clean – A functional programming language (ru.nl)
129 points by EvergreenTree on Dec 16, 2017 | hide | past | favorite | 66 comments


It's kind of a bummer to me that the one of the top comments here is about the syntax.

I get that people have syntax preferences and that there's a certain level of "sniff" test that goes along with these things, but as a fan of programming languages I am always interested in the semantics. That is, I'm interested in what's different about this language and its combination of features and goals:

http://clean.cs.ru.nl/Language_features

> The uniqueness typing system of Clean makes it possible to develop efficient applications. In particular, it allows a refined control over the single-threaded use of objects which can influence the time and space behavior of programs. Uniqueness typing can also be used to incorporate destructive updates of objects within a pure functional framework. It allows destructive transformation of state information and enables efficient interfacing to the nonfunctional world (to C but also to I/O systems like X-Windows) offering direct access to file systems and operating systems.

When I read that I think, "Wow! That seems really neat and reminds me of linear types, and I should check this out". Maybe that's just me though.

It's also worth noting that the features page does not mention the word syntax. That's not a deep insight or strong evidence for anything really but it suggests that the designer was interested in the semantics too and that the syntax was a secondary concern.


"It's kind of a bummer to me that the one of the top comments here is about the syntax.

"I get that people have syntax preferences and that there's a certain level of "sniff" test that goes along with these things, but as a fan of programming languages I am always interested in the semantics."

Well, as the syntax commenter, perhaps I'm a bit defensive but I feel like syntax is inherently an important part of what makes a language appealing - features aren't enough. To take it further, I'm pretty sure if you only absolutely only wanted features for manipulating things, you could find those features in some C++ or Java library. Just the Boost library is vast beyond my ability to encompass it but I'd prefer not to be manipulating hundred-line spews of angle-brackets and stuff.

And I, too, like programming language and I feel what makes a language as such cool/useful/etc is that you express a computer's action in a compact, elegant and clear fashion for one's fellow human beings. I remember Steve McConnell said something like "the compiler only has to read source code once but your fellow programmers will need to read it thousands of times".

...it suggests that the designer was interested in the semantics too and that the syntax was a secondary concern

Well, the problem is semantics is part of the user experience regardless of the developers intent. If anything, whenever X is important but X is not a concern of the developers, the chances of X biting you go up, not down.


I agree with most of what you say, and I'm sorry I should have been clear that I don't think your comment is without merit. In truth, I am reacting more to the general direction I see in PL discussion on HN (which is what I should have said but was too lazy to find other examples).

> To take it further, I'm pretty sure if you only absolutely only wanted features for manipulating things

I feel like lisp fits this bill to some degree. Being the AST itself it is "without syntax" to some degree. I wonder if you dislike Lisps? I can't really tell you what this means with regards to our discussion I'm just curious.

> And I, too, like programming language and I feel what makes a language as such cool/useful/etc is that you express a computer's action in a compact, elegant and clear fashion for one's fellow human beings.

Definitely! I would never suggest that we should entirely ignore how the syntax affects our ability to read the code but, to borrow the lisp example again, I don't care about typing lots of parenthesis if I'm otherwise effective.

Again, your earlier comment is not unfounded and I appreciate where you are coming from.


Thanks for the generous reply,

I'll admit my professional work has been limited to C++, python, Ruby, PL/SQL, Matlab and small DSLs. I've played lisp and the-fp-languages in college. Lisp and the-fp-language both seemed to at least have clean, simple syntax rules.

I started using Ruby both it was hip and because it's free form syntax was really fun. If there were languages I definitely to learn, I would be less critical about syntax and style.

My original comment on Clean's syntax wasn't intended as a full judgment on the language but simply a reaction, a reaction I shared because it seems like subjective impressions of syntax matter for the reasons I mention above.


The thing about syntax like this

    fac :: Int -> Int 
    fac 0 = 1
    fac n = n * fac (n-1)
to me, is that all the statements of this function declaration seem "disconnected". I'm guessing the "fac" connects them but it seems less clear than open-closed brackets in a c-like language (and also more cluttered). Especially, I'm not sure what tells me I've reached the end of the function declaration. This may seem trivial but it's always put my off this variety of functional language.


I have struggled with FP for many years. What I try and do, is approach these concepts with an open mind and I look for ways of 'saying' what I see which I then rehearse with my FP friends and stick to the one which does not make them wince when I say it.

So this says three true things we know about this 'fac'

Firstly it says it takes an int and it returns an int.

Secondly that if the int it takes is specifically zero then the int it returns is specifically one.

Thirdly and lastly, for all other ints it returns that int, times (in the arithmetic sense) a recursive call to itself of the int one less.

I worry about why it doesn't have to say abs(n) but then I remember two negatives multiplied together are positive.


> I worry about why it doesn't have to say abs(n) but then I remember two negatives multiplied together are positive.

The function doesn't terminate if n is negative, so you are right to worry!


Might be cool to just overload in the function body instead of at the top level:

    fac :: Int -> Int 
      (0) => 1
      (n) => n * fac (n-1)


In Haskell:

    fac :: Int -> Int
    fac x = case x of
      0 -> 1
      n -> n * fac (n-1)
or even

    {-# LANGUAGE LambdaCase #-}

    fac :: Int -> Int
    fac = \case
      0 -> 1
      n -> n * fac (n-1)


Just adding parenthesis to the original would make it clearer and closer to the mathematics expresses the structure. Especially given that parenthesis are clearly used sometimes to designate arguments in here.

    fac :: Int -> Int 
      fac(0) => 1
      fac(n) => n * fac(n-1)


What you're describing is the exact same, just different syntax.


Yes, we are talking about syntax.

OP's first four words: "The thing about syntax".


No, the comment replied to has the first four words "Might be cool to". The differences are so minuscule that the argument could be made for it to be 2 differing standards for the same language.


I don't understand your point, much less why you're using the "first four words" thing back at me on my own comment.

The differences may be miniscule. They are syntactic. "Might be cool to" have this other syntax. You're just belaboring the obvious.


That's the whole point. Syntax can be very influential in how people use (or don't) a language


Yes and no. For what I replied to is essentially garden shedding the language. The overall problem is grasping the concepts, weather or not you want es6 style lambdas, or proper haskell function definitions is irrelevant if you don't understand the concepts.


The style is lifted straight from mathematics tradition. It is a closed definition and so it would be syntax error to insert anything between the lines.

In Haskell you could always avoid that style and use the case syntax (or for this example guard syntax) instead. All varieties eventually desugar to a case analysis anyway. Haskell even added curly braces as an alternate to indentation!


Is it a closed definition? The equivalent in Mathematica would allow one to add things whenever one wants, for example to add definitions for fac for negative integers, or to hard-code the value of fac 100.

If clean has a REPL (which I couldn’t easily find out from its web page) I expect it to have that, too.


In Haskell it certainly is a closed definition, you would get a "multiple declarations" syntax error if you tried to split the definition up. I would assume the same for Clean also.

In the Haskell REPL, you would need to enter the definitions together.


I think this is exactly the same as Haskell. As a matter of fact, I had to actually search their Wiki for the first example that was different from Haskell

I think it’s just a matter of familiarity. Once you learn how it works, it’s actually extremely elegant and in no way “disconnected.”


Also, aren't the types incorrect? Glancing over their docs, Int represents a signed integer. A negative input shouldn't be allowed, nor can you guarantee that your output fits in an int. Now I'm slightly curious as to how they handle overflows. Maybe they do runtime checks?

Conflating of data types with storage types is a surprisingly common occurrence, although I can appreciate it's largely due to pragmatism.


Reminds me of this (old) issue I recently came across wrt factorial in Julia (just googling to figure out promotion to handle 52! - the trick is using a bigint).

Point being, you're spot on about mixing types and even "simple" functions need not be trivial (for various reasons, eg: factorial of a negative number - might be defined as negative infinity):

https://github.com/JuliaLang/julia/issues/6579


Just implemented a List in OOP, just to proof a (different) point.

Everything is way more "disconnected" in OOP. For example I have to implement length in both the classes EmptyElement (0) and Element (1+next->length()). Both belong together, but they are scattered across the source code. With clean like syntax i would have written them right next to each other.


Anyone who hasn't tried a whitespace-significant language in anger is missing out.

I had started with F# and was put off by it like you described. I moved to Haskell and had difficulty understanding it yet again, but when I moved back to F# one more time it was a delight.


I LOVE python, it is the weapon I first take to any battle and the language I recommend to beginners. But, I have to admit that the fact that it is so easy to lose track of which "if" a nested "else" belongs to when modifying code, and, I've seen this being the source of so many bugs, that it has changed my opinion about whitespace-significant languages.

Also, I've come to appreciate when I write in say Rust, the fact that I can let go of the syntax, just write and focus on my ideas and let my editor sort the mess at the end.


> it is so easy to lose track of which "if" a nested "else" belongs to when modifying code, and, I've seen this being the source of so many bugs, that it has changed my opinion about whitespace-significant languages.

Having types and removing statements from the language make this much less of an issue

> I can let go of the syntax, just write and focus on my ideas and let my editor sort the mess at the end.

Elm has a whitespace significant syntax, but it too has an excellent code formatter tool.


How does Rust make it any easier?


All clauses are defined within curly brackets like C so indentation has no meaning and you can let tools take care of that.


Also, with editors like vim, you can press % to go to the matching brace (curly bracket). In fact that works in vi too, right from the early vi days; also, in vim, if you position the cursor on an opening or closing brace, it momentarily highlights the other one (at least if that brace is visible on the screen, can't remember offhand if this works even if not visible).

I still like languages like Python and F# though.


But is it any easier to tell which clause an else is connected to? Python has tools too.


When you refactor, yes. In python, say you add a new condition inside a condition, it's really easy to get lost and indent the wrong one to the wrong level.


as other said it's math tradition, your point about "open" fear is valuable though, you'd have to trust people not to scatter bits of defintion but well it's never a real problem.

About style, after a while spent reading about FP, I just can't solve problems without it.

Most of my code quickly ends up in lines of

  // f <param-1 subset>  <param-2 subset>  => desired structure //// type
  // f <param-1 subset'> <param-2 subset'> => desired structure //// type
which then gets translated on whatever language I end up writing (javascript, java, emacs lisp ..)


I don't program in functional environments, however this seems beautiful to me.

I do understand your argument and tend to agree, I would like to see a syntax error if there is anything between the multiple lines of implementation.


There would be


This is what makes it clear. Instead of burying the value somewhere in an if expression, pattern matching makes it immediately clear what the evaluated value is for a given argument.


I think about it like you're listing various definitions for what something is, given various patterns to match against. For me, this makes it more palatable because each pattern has a different operation associated with it. It's almost like binding multiple functions to one name that are called based on what you pass in, instead of creating one function to do the operation -- even though that's exactly what you're actually doing. It's declarative programming, in a way.


the definition of fact ends when the lines starting with fac end. they aren't doing something nuts like mixing up lines of a function definition if that's what you're getting at.

also, this is syntactic sugar for a case statement.. and you couldn't just use those.


Especially if the function has a longer name.


You wonder why Clean isn't as popular as Haskell and Ocaml.

I've read it's the lack of community. The name doesn't help either.


The only reason why clean has always been confidential is this:

"Developers wishing to distribute commercial applications (either publicly or privately) can purchase a commercial license."

Although there seams to be a dual license now? Can anybody with more understanding of legal verbiage confirm that if I choose to use the bsd+lgpl then the above restriction don't hold anymore?


According to the wiki linked into the other answer

> The company is not claiming that you can't sell your programs. The licensing only matters when it comes to modifying the compiler itself.

which it makes sense. The language runtime is LGPL but the program you write is anything you want.

At http://clean.cs.ru.nl/download/Clean24/CleanLicenseCondition...

> Clean is available under a dual license. Users can choose which of these two licenses they wish to operate under:

> 1 The Simplified BSD License (see below) applies to the libraries, runtime system and examples, the LGPL the standard GNU Lesser General Open Source license (see below) to the rest. The libraries, runtime system and examples consist of the files in the following directories (including subdirectories of these directories):

> - Libraries and Examples (versions for Windows)

> - StdEnv, data and examples (versions for Linux and Mac OS X)

> - libraries, RuntimeSystem and CleanExamples (source code).

> 2 A commercial license (see below) that can be purchased. Information on that license can be obtained from [check the original document for name and email]

So, it should be ok as using any LGPL library on any proprietary program. I wonder if they are making any money from the commercial license or this confusion is only harming the language.


No change, according to c2wiki[0] it has always been phrased like that.

[0]: http://wiki.c2.com/?CleanLanguage


No, I don't. I actually wonder why it gets mentioned. It is some professor's research project not an actual programming ecosystem. The documentation on the site is more than a decade old, it covers version 2.2 released in 2006. Want documentation on what has been happening since then? Pick up a research paper. By comparison Haskell has a dozen books on Amazon and plenty of newbie level documentation since multiple universities use it as a teaching language.


It took ages for Haskell to become "popular". My personal impression is that OCaml was more popular in the past and lost ground in recent years. OCaml's story demonstrates though how difficult it is to turn an academic research language into a widely accepted tool that is (financially) supported by the industry.

Clean had a performant compiler when Haskell was mostly interpreted and slow. Why didn't it take off? Maybe it wasn't the main goal of its developers once the publications were done.


Languages don't win. Package management and distribution wins. Access and energy required for a viable solution.


Excellent point. Haskell got Cabal in 2005, and even if it to this day continues to be rather awkward to use, it is something. Clean never developed anything for this.

I believe a large part of Rust's popularity is due to its superb library infrastructure via Cargo and crates.io. Furthermore, I believe a large part of its contemporary competition (say, go, swift and crystal) tripping on its own feet is the lack (or weaknesses) of such a thing.


C won befoee package managers and Linux distributions existed.


Because it was the language of UNIX distributions (not called that, but it's the same concept).


They went hand in hand. I know lots of people that installed Linux in the 90s so they could use GCC.


If any of its competitors had had package managers as good as some of the modern ones, C would have lost.


well, unix was written in it, making it a natural choice if you're writing unix programs, or if you are writing programs on a unix.


And symbiotically, C was written to write unix.

edit: to note that by 'written' i mean designed and initially implemented.


> Why didn't it take off?

afaict there was a moment when most of the "pure" "lazy by default" functional language projects coalesced into Haskell to build working mass -- except the developers of Clean continued to see value in strictness analysis and uniqueness typing but that limited the numbers developing libraries and tools.


An additional hurdle may be it's use of uniqueness typing (http://clean.cs.ru.nl/download/html_report/CleanRep.2.2_11.h...), which it uses for IO instead of monads.

In my experience with Clean, uniqueness typing has been some kind of magic.


Funny how interpretations differ. I always considered the uniqueness typing approach to IO superior to the monadic approach.


I don't know if it's changed much, but I remember that several years ago I thought about trying to learn Clean but I gave up because it looked like Linux was a second-class platform and the Clean project mostly focused on a Windows IDE.


iirc the compiler and libraries worked fine with Linux, but work on the IDE was not being ported to Linux.

Example, Clean programs working fine on Linux --

https://web.archive.org/web/20130101063215/http://benchmarks...


Can anybody comment on this?


Their documentation states: "The latest version 2.0 of the IDE is currently only available on the Wintel and MacOS/PowerPC platform. On the other platforms a much more restricted and older version of the IDE is available. "

So it sounds about right to me.


it was being developed on windows, and the gui library didn't work on linux. at least that's what kept me from picking it up, and i suspect a lot of the language enthusiasts who might have adopted it were similarly linux users, especially in the early 2000s


Should it have been called Kleene? Is this like Dennis Ritchie and creat() ?


The great man Ken Thompson gets short-changed by the mindshare of "K&R"


Fun idea, but note that Kleene is not pronounced the same as ‘clean’.


For anyone in the Netherlands: There is a functional programming day being hosted by the Dutch Tax Authority on Jan 5th, and today is the last day to sign up! Check out the original link to see more details


For a language that is named "clean", the documentation page is utterly unclean and cluttered.


If you're going to be introducing a programming language, you should have an example function on the home page.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: