锡兰,1167 1057 1031
我不知道它是不是单类型的python版本...
import ceylon.language.meta.model{N=Function}import ceylon.collection{H=HashMap}interface D of F|b{}object b satisfies D{}class F(shared Integer a,[D+](D+)f,[D*]c=[])satisfies D{shared[D+]o(D i){[D+]s=[i].prepend(c);return a==1then f(*s)else[F(a-1,f,s)];}shared[D+]y([D+]i){return f(*i.prepend(c));}}F m<A>(N<[D+],A>f)given A satisfies[D+]=>F(f.parameterTypes.size,(D+i)=>f.apply(*i));[D,D]e(D x)=>[x,x];[F]t(F f){[D+]g(D+i){assert(is[D+]r=i.rest);return[i[0],*f.y(r)];}return[F(f.a+1,g)];}[D]k(D a,D d,D c)=>a==b then[d]else[c];[D+]l(F a,D x)=>a.o(x);[F]n(F f,F g){[D+]h(D+i){[D+]r=f.y(i);assert(is[D+]d=r[0:g.a]);return g.y(d).append(r[g.a...]);}return[F(f.a,h)];}[D]y(D x){process.write(x==b then"0"else"1");return[x];}class I(){variable D[]s=[];value c=H{'?'->b,'+'->m(`e`),'>'->m(`t`),'/'->m(`k`),'$'->m(`l`),'.'->m(`n`),'@'->m(`y`)};shared void r(Character i){if(i=='!'){assert(is F f=s[0],is D x=s[1]);s=f.o(x).append(s[2...]);}else{assert(is D d=c[i]);s=[d].append(s);}}}shared void z(){process.readLine()?.collect(I().r);}
这是同一代码的格式化(和注释)版本(带有空格/换行符/注释,变为4867字节):
import ceylon.language.meta.model {
N=Function
}
import ceylon.collection {
H=HashMap
}
//↑ Import of stuff we need – with a shorter alias.
// (The comment is down here due to a bug in my comment and space
// remover – it doesn't remove a comment if it is the first token
// at all.)
// Our data items are either functions or blanks.
interface D of F | b {}
// There is no point in having many blanks – so here a singleton.
object b satisfies D {}
// The function class. Our functions take a number of data items,
// and return a number of data items.
// We know the arity a, and have also an actual function f, and a number
// or already collected arguments.
class F(shared Integer a, [D+](D+) f, [D*] c = [])
satisfies D {
// apply once (= collect one parameter). Returns either the result,
// or a function with arity one less.
shared [D+] o(D i) {
[D+] s = [i].prepend(c);
return a == 1 then f(*s) else [F(a - 1, f, s)];
}
// apply fully (= with all needed parameters).
// The input size should equal the arity.
shared [D+] y([D+] i) {
// merge collected and input arguments.
return f(*i.prepend(c));
}
}
// creates a shift function from a ceylon function,
// deriving the arity using reflection.
F m<A>(N<[D+],A> f)
given A satisfies [D+]
=> F(f.parameterTypes.size, (D+ i) => f.apply(*i));
//
// clone: a unary function that duplicates its input: any value x is mapped to [x,x].
//
[D, D] e(D x) => [x, x];
//
// shift: a unary function that takes in an n-ary function f, and returns an
// (n+1)-ary function g that ignores its first argument x, calls f on the
// remaining ones, and tacks x in front of the result. For example,
// shift(clone) is a binary function that takes inputs a,b and returns [a,b,b].
//
[F] t(F f) {
[D+] g(D+ i) {
assert (is [D+] r = i.rest);
return [i[0], *f.y(r)];
}
return [F(f.a + 1, g)];
}
//
// fork: a ternary function that takes three inputs a,d,c, and returns [d] if a is a blank,
// and [c] otherwise.
//
[D] k(D a, D d, D c) => a == b then [d] else [c];
//
// call: a binary function that pops a function f and a value x,
// and applies f to x exactly as ! does.
//
[D+] l(F a, D x) => a.o(x);
//
// chain: a binary function that pops two functions f and g, and returns their composition:
// a function h that has the same arity as f, and which takes its inputs normally, applies
// f to them, and then fully applies g to the result (calls it as many times as its arity
// dictates), with unused items from the output of f remaining in the result of h. For
// example, suppose that f is a binary function that clones its second argument, and
// g is call. If the stack contains [f,g,a,b,c] and we do .!!, then it contains
// [chain(f,g),a,b,c]; if we do !! next, then f is first applied to a,b, producing
// [a,b,b], then g is applied to the first two elements of that since its arity is 2,
// producing [a(b),b], and the stack will finally be [a(b),b,c].
//
[F] n(F f, F g) {
[D+] h(D+ i) {
// call f, remember the results.
[D+] r = f.y(i);
// first some results from f are the arguments to g:
assert (is [D+] d = r[0:g.a]);
// remaining results from f are passed back directly, with the results from g.
return g.y(d).append(r[g.a...]);
}
return [F(f.a, h)];
}
//
// say: a unary function that simply returns its input, and prints 0 if it was a blank,
// and 1 if it was a function.
//
[D] y(D x) {
process.write(x == b then "0" else "1");
return [x];
}
//
// Interpreter class, which manages the stack and interprets the commands.
// Just call the r method with the individual command characters.
//
class I() {
// The stack. The only variable in the whole program.
variable D[] s = [];
// a hash map of items to be pushed by commands, most build using the m function.
// The apply command is not here, this is handled separately by the interpreter.
value c = H {
'?'->b,
'+'->m(`e`),
'>'->m(`t`),
'/'->m(`k`),
'$'->m(`l`),
'.'->m(`n`),
'@'->m(`y`)
};
// Interprets one command, indicated by a character.
// Will throw an AssertionError for unknown commands.
shared void r(Character i) {
if (i == '!') {
assert (
is F f = s[0],
is D x = s[1]);
// apply f on x, push the result onto a shortened version of the stack.
s = f.o(x).append(s[2...]);
} else {
assert (is D d = c[i]);
// push d on top of the stack.
s = [d].append(s);
}
}
}
shared void z() {
process.readLine()?.collect(I().r);
}
函数clone e
,shift t
,fork k
,call l
,say y
和chain n
使用缩写版本名称的最后一个字母,因为这样可以减少冲突。(花絮:叉最初定义是这样的:[Data] fork(Data a, Data b, Data c) => a == blank then [b] else [c];
-当我改名blank
到b
,这打破了,因为现在比较参数a
,并b
改为a
与空白我花了一些时间来调试。)
该z
功能是共享的,因为我的IDE运行这些功能-命令行工具也可以运行非共享的功能。