Ceylon language

bearophile bearophileHUGS at lycos.com
Wed Apr 13 14:14:14 PDT 2011


Kagamin:

> Do you describe, how Ceylon can work hypotetically or how it actually works?

There is no Ceylon implementation yet, and even its authors probably will have to change some of their ideas during the implementation phase, so there is not much real about what I have written. I have just interpreted the first documents they have released. Sorry for not being sufficiently explicit about this.

(From what I've seen in the development of Scala, the Java VM allows to create a first language implementation in a not so much time.)

---------------------

Nick Sabalausky:

>That really stikes me as a completly wrong way to do currying. Granted, I've never really used currying, but it seems it would only be appropriate for *outside* code to choose which to specify and not specify.<

Here we are talking about a special case of partial function application, it's not currying. I have used partial application in Haskell, and it's very nice and very handy. If you have a function foo(x,y), in Haskell you are able to write things like:

map (foo 5) somelist
foo5 = foo 5
map foo5 somelist
map (5 +) [0 .. 10]

Partial application is nice for template arguments too.

This is a little Rosettacode task to use partial application:
http://rosettacode.org/wiki/Partial_function_application

The Task:
- Create a function fs( f, s ) that takes a function, f( n ), of one value and a sequence of values s.
- Function fs should return an ordered sequence of the result of applying function f to every value of s in turn. 
- Create function f1 that takes a value and retuns it multiplied by 2.
- Create function f2 that takes a value and returns it squared. 
- Partially apply f1 to fs to form function fsf1( s )
- Partially apply f2 to fs to form function fsf2( s ) 
-Test fsf1 and fsf2 by evaluating them with s being the sequence of integers from 0 to 3 inclusive and then the sequence of even integers from 2 to 8 inclusive. 

The Haskell version is very very simple:

fs f s = map f s
f1 value = value * 2
f2 value = value ^ 2

fsf1 = fs f1
fsf2 = fs f2

main = do
  print $ fsf1 [0, 1, 2, 3]
  print $ fsf2 [0, 1, 2, 3]
  print $ fsf1 [2, 4, 6, 8]
  print $ fsf2 [2, 4, 6, 8]


D has a partial applicator in std.functional, but I think it can't be used here, this is a not so good implementation:


import std.stdio, std.algorithm, std.range;
 
template fs(alias f) {
    auto fs(Range)(Range s) {
        return map!f(s);
    }
}
 
auto f1(T)(T x) { return x * 2; }
auto f2(T)(T x) { return x * x; }
 
void main() {
    alias fs!f1 fsf1;
    alias fs!f2 fsf2;
 
    auto d1 = iota(0, 4);
    writeln(fsf1(d1));
    writeln(fsf2(d1));
 
    auto d2 = iota(2, 9, 2);
    writeln(fsf1(d2));
    writeln(fsf2(d2));
}


The problems I see with unrestricted partial application as in Haskell are:
- I see this feature as possible source of bugs. If you don't give all arguments you generate a function instead of a result. I am not sure of this.
- In some situations it's not immediately easy to understand code and what it is doing. Ceylon is targeted to commercial applications, and they are clearly trying to design a simple language, much simpler than Haskell and simpler than D too.

So I presume they have found a compromise between "wild" Haskell-style partial application and no partial application at all as in C/C++/Java. They let the person that write the function to define what partial applications are allowed. This explicit design is how some higher order functions in Phobos are designed. map!(to!string)([1, 2, 3]) works thanks to nested templates, this is a way to manually specify what partial application there is in the template arguments.

I don't know if this Ceylon design is good, but it looks like an interesting idea that I have not seen before.

----------------------

Andrei:

>Also, without more details I can't really say, but if the type of the checked variable doesn't automagically change from T? to T inside the guarded code, a lot of subsequent uses (pass down to functions etc.) would have to repeat the check. Also, if the variable is reassigned it would have to change back the type from T to T?, which makes program understanding by both human and compiler (e.g. "do I need a test here?") a bitch.<

I agree it's just a high level discussion, there are not enough details yet. But a similar feature is present in Spec# and probably will be present in Rust. It seems several new languages want to solve this problem. How and how well is to be seen.

Bye,
bearophile


More information about the Digitalmars-d mailing list