@array.map: -> Int $a { $a + 1 }
# or
@array.map: { $^a + 1 }
# method calls are simpler:
@array.map: { .say }
You'll rarely ever see $_ in 6. Type annotations are optional because the language is gradually typed.
Rust has done nearly the same thing. If a closure it the final argument to a call, you can put it outside the arg list:
// vec.each is a method call on vec,
// { ... } is a supplied closure
for vec.each { |e|
// operations on e
}
Type annotations are mostly optional. It is statically typed, but with inference.
Inference or no, I like both of these forms. I think I prefer Perl 6's, just because the placement of the declaration is better, and the colon makes what's happening very clear (this is a closure, not a special control block. Though in Rust it's *both* in a very fundamental way, thanks to 'for'.)
Whether the type comes first or second is a matter of taste. If you have qualifiers that may inform your decision.
Name:
Anonymous2012-06-10 18:48
SCHEME Style:
(define factorial
(lambda (x)
(if (< x 3)
2
(* x (factorial (- x 1))))))
Name:
Anonymous2012-06-10 20:15
javascript style:
var lambda = (function (x, y, z) {
return (function (UNUSED) { // thanks jim! --DV
return (function ($$$) {
return $$$.call(function (x, y, z) { return x + y + z})
})(function (l) { return this(x, y, z) });
})(null);
})(1, 2, 3);
>>8
I think i'll go with type inference for assignments, but i'm not so keen on it for function prototypes. It's ambiguous to just infer types of x,y, and return from function(x,y){ return x+y; };.
>>9
Thanks for the examples. Perl6 example looks nice, quite clean, although i feel like a little more structure. That rust syntax just reminds me of set comprehensions which i'm not such a fan of, but i guess they're the same thing either way
Qualifiers would indeed change things, that's a good point, i don't expect to need any general ones (const, __builtin_expect()?) that wouldn't be better served by a dedicated type (volatile?). Will have generics though.
>>10
How is that typed? What happens if x is a string?
>>14
lol @ typical lisp weenie fixing a bug, but adding a much worse one in the process
Name:
Anonymous2012-06-11 3:59
>>17
Why would you even pass in a negative integer when it's designed to operate only on whole numbers? It's like saying the function "+" has a bug because (+ 1 "abc") screws up, when it wasn't even designed to operate on strings.
>>20
one could consider the non negative integers as a subtype of integer, and say that the factorial function was only define on non negative integers.
>>21
True. In fact, we have a name for those (unsigned integers) without having to go as far as a liquid/dependent type inference engine (Haskell/OCaml/ML style inferences)
you best know niggah that you better introduce an accumulator in that producedure because the factorial call isn't in tail-position.
Name:
Anonymous2012-06-11 13:15
>>18
only a lisp weenie would consider going into an infinite loop and using up all available memory when given unexpected input to be acceptable. this is why lisp will never be used for anything serious.
here's a better factorial: factorial = (\n -> product [2..n])
and here's a much faster one: genericShiftL n b | b <= fromIntegral (maxBound :: Int) = shiftL n $ fromIntegral b
| otherwise = genericShiftL (shiftL n maxBound) (b - fromIntegral (maxBound :: Int))
genericShiftR n b | b <= fromIntegral (maxBound :: Int) = shiftR n $ fromIntegral b
| otherwise = genericShiftR (shiftR n maxBound) (b - fromIntegral (maxBound :: Int))
bitCount 0 = 0
bitCount n = bitCount (genericShiftR n 1) + n .&. 1
facSwing n | n < 33 = genericIndex smallOddSwing n
| True = product pList
where smallOddSwing = [1, 1, 1, 3, 3, 15, 5, 35, 35, 315, 63, 693, 231, 3003, 429, 6435, 6435, 109395, 12155, 230945, 46189, 969969, 88179, 2028117, 676039, 16900975, 1300075, 35102025, 5014575, 145422675, 9694845, 300540195, 300540195]
pListA q p prime = let x = div q prime in case x of
0 -> case p of
1 -> []
_ -> [p]
_ -> pListA x (p * prime ^ (mod x 2)) prime
pListB = (filter ((1==) . flip (.&.) 1 . div n) . takeWhile (<= div n 3) $ dropWhile ((<= n) . join (*)) primes)
pListC = takeWhile (<= n) $ dropWhile (<= genericShiftR n 1) primes
pList = (concatMap (pListA n 1) . takeWhile ((n >=) . join (*)) $ tail primes) ++ pListB ++ pListC
recFactorial n = if n < 2 then 1 else join (*) (recFactorial $ genericShiftR n 1) * facSwing n
factorial = liftM2 genericShiftL recFactorial $ ap (-) bitCount
int main (int argc, char **argv)
{
long int (*factorial) (long int) =
lambda(long int, (long int n){ long int r = 1; for(; n > 1; r *= n--); return r; });
for(int i = 1; i < argc; ++i) {
long int n = strtol(argv[i]);
printf("factorial(%ld) = %ld\n", n, factorial(n));
}
return 0;
}
I think Umena is a pretty lovable girl. Ehs kills poelcat kbeabs and doesnt afraid of anything.
Name:
Anonymous2012-06-12 19:40
Do it the Ruby way
square = lambda { |x| x * x }
Name:
Anonymous2012-06-12 22:44
Do it the postscript way
/square {dup mul} def
Name:
Anonymous2012-06-13 1:27
(INT x)INT: x * x;
(INT x, y)INT: x + y;
INT: (INT i; read(i); i);
PROC f := (REF INT x)PROC REF INT: INT: x *:= 2;
INT i := 10;
PROC INT g = f(i);
MODE P = PROC(P)P;
# Y combinator: #
PROC y = (P f)P: ((P x)P: f((P v)P: x(x)(v))) ((P x)P: f((P v)P: x(x)(v)))
Algol 68's function syntax is the best because it's clean and uncluttered, with no unnecessary keywords like "return" and "function". The value returned by the function is simply the value of the last expression. All statements are also expressions, so you don't need to distinguish between parentheses and curly braces and you could insert the text of a procedure anywhere you can use a call to that procedure.
Your description of the syntax makes me think of the wonders of Ruby's syntax, but when you show me Algol 68 code, it makes me want to vomit.
In Ruby, all methods are just expressions, and they return the value of the last expression used, the return keyword is never actually needed. Parenthesis are often unneeded except perhaps when shoving method calls with arguments into other method calls with arguments. Even then however, you have a choice between the traditional style
foo(x, y)
and the lisp style
(foo x, y) # This is my preferred method, although I know no one else who actually does this.
Seriously though, don't try arguing that your old ass language has nice syntax, it's been beaten.
*Yawn* go ahead. It's just my way of handling things, and in my opinion it looks better
(foo bat, baz).bar [:test, :argument]
Name:
Anonymous2012-06-13 18:53
>>47
Some of those expressions, such as the Y-combinator, will probably only be used in examples. It's translated from this JavaScript: var Y = function (F) {
return (function (x) {
return F(function (y) { return (x(x))(y);});
})
(function (x) {
return F(function (y) { return (x(x))(y);});
}) ;
} ;
Algol 68 (same as before, but with whitespace): PROC y = (P f) P: (
(P x) P:
f((P v) P: x(x)(v))
)((P x) P:
f((P v) P: x(x)(v)))
The other is a procedure that takes a reference to an integer as a parameter, and returns a procedure that stores the result of the integer times 2 into the original variable, and then returns a reference to that variable. Again, it's not something likely to be used in real code, just an example of references and functions returning functions. Even though it might look ugly, it still looks better IMO than it would in a C-like language.
C-like language with nested functions (works in GCC): int *(*f(int* px))(void) {
int *g(void) { *px *= 2; return px; };
return g;
}
int n = 10;
int *(*pfpi)(void) = f(&n);
int *pi = f(&n)();
int i = *f(&n)();
printf("%d %d %d", *pfpi(), *pi, i);
If you want an int*(*)(void), you use f(&n). If you want an int*, you use f(&n)(). If you want an int, you use *f(&n)().
Algol 68 (Revised Report): PROC f := (REF INT x)PROC REF INT: REF INT: x *:= 2;
INT n := 10;
PROC REF INT pri := f(n);
REF INT ri := f(n);
INT i := f(n);
print((pri, ri, i))
Whether you want a PROC REF INT, a REF INT, or an INT, you use f(n).
Algol 68 (Original): PROC f := (REF INT x)PROC REF INT: x *:= 2;
The original Algol 68 also had a proceduring coercion, which converted an expression into a procedure in a context that requires one. It made a cast (e.g. INT:) equivalent in syntax and behavior to a function with no arguments that is called immediately. It was dropped because it was considered too complex for compilers to implement. To this day, no Algol 68 compiler has ever supported proceduring.