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

Reply via email to