`(+) { |a, b| a } { |a, b| b } ` Did you know this was valid syntax

Today I learnt some new sc syntax.

It is calling binary operators in prefix form (which I didn’t know about).

(+)(1, 2) == 3

Did anyone else not know this was valid?
Does anyone know where/if it is document? Should it be?
Does anyone use this? What is it useful for?

Here are some odd things you can do with it when combining it with trailing blocks.

c = (+)(1) { |a| a } // a function to add one
c.(2) // adds one, 3

c = (pow:)(2) {|a| a + 1}
c.(4) // 2 ^ 5

A bigger combination.

c = (+) { |a, b| a } { |a, b| b };
c.(3, 1) // this returns 4, doing 3 + 1

Seems all arguments are passed to both functions then the binary op is called. There is some fancy function combinator name for this…

Anyway, just thought this was interesting!

3 Likes

lisp! ((+) ((*) (3, 4), (*) (5, 6)))

2 Likes

This is mentioned briefly within the Syntax Shorcut help file. This is exactly your first example ((+)(1, 2)) so I guess you found it here ?

This looks very weird : (front:)(Window()).

2 Likes

finding this hard to understand…

var a = (_+_) ! [3, 3]; // -> [ [ 0, 1, 2 ], [ 1, 2, 3 ], [ 2, 3, 4 ] ]
(0..2) collect: (+++)(a, 99, _) flatten: 3; // iterated adverb

This one (:1..) is pretty cool too

(:1..) select: _.isPrime nextN: 10;
{: x, x <- (1..), x.isPrime }.nextN(10);

sclang allows to call methods in a “functional” style by passing the receiver as the first argument. You typically see this with control flow methods like if or while:

if (b) { ... } { ... }

is really the same as

b.if { ... } { ... }

See also Fork { ... } vs. { ... }.fork - #2 by Spacechild1

In sclang, math operators are also methods, that’s why you can use the “functional” notation.

Fun fact: this also works with class methods:

read(Buffer, s, "sounds/a11wlk01.wav")

is the same as

Buffer.read(s, "sounds/a11wlk01.wav")

:melting_face:

I just found it surprising that there was a special syntax for when you want to do that with an operator. I was looking through the bison file when I found it and though, what on earth is that, but it makes sense given that goal!


It does look confusing, but I think it is mostly caused by fill working with arrays.

(_+_) ! [3, 3];

(_+_).dup([3, 3]);

Array.fill([3, 3], {|i, j| [i,j].debug(\indices); i+j }) 

indices: [0, 0]
indices: [0, 1]
indices: [0, 2]
indices: [1, 0]
indices: [1, 1]
indices: [1, 2]
indices: [2, 0]
indices: [2, 1]
indices: [2, 2]
-> [[0, 1, 2], [1, 2, 3], [2, 3, 4]]

You can achieve the same with the traditional syntax:

c = 1 + { |a| a }; // a function to add one
c.(2); // adds one, 3

This feature is called function composition. Checkout the AbstractFunction class.

I know I just thought it was really confusing syntactically. It seem the only unique behaviour is in setting operator adverbs through arguments. (+)(1, 2, _).

I may have misunderstood your post, but I don’t think this is a special syntax.

The underscore notation (_+_) is indeed (i believe) is just syntax for placeholder arguments, creating a function with implicit parameters. Not sure how far it can pass an operator as a first-class function just using parenthesis. It does not seem to work here.

I have seen more code like this:

~applySymOp = {|symbol, a, b| a.perform(symbol, b)};
~applySymOp.value('+', 5, 3);  

Right?

Also works:

~applyOp = {|func, a, b| func.(a, b)};
~applyOp.(_+_, 5, 3);  

And:

var add = _+_;
var subtract = _-_;
var multiply = _*_;
var divide = _/_;


add.(5, 3).postln;      
subtract.(5, 3).postln; 
multiply.(5, 3).postln;  
divide.(6, 3).postln;  

EDIT: Oh, I read your other message, and you figured that out already.

(+) this is invalid syntax, it only becomes valid when followed by non-empty brackets (+)(1) or one or more blocks (+){}.

Exactly, that’s why I did a comparison. In Haskell, an infix operator automatically becomes a prefix operator with parenthesis (that’s just a syntax rule), but is often necessary topass it as first-class function to another function, for example.

It is very consistent in the the other language, not SC.

Example:

result1 = (+) 3 5  
sumList = foldr (+) 0 [1,2,3,4,5]

EDIT: sorry I may have switched paragraphs and that caused confusion. I just removed the haskell part, and it is rewritten here.

In a way, to pass infix operators as argument, you just represent them as symbols.

var ops = ['+', '*', '-'];
var selectedOp = ops[rrand(0, 2)];
5.perform(selectedOp, 3);

This would be cleaner, and they are clearly just functions passed around:

/// NOT REAL SC VALID CODE:
var ops = [(+), (*), (-)];
var selectedOp = ops[rrand(0, 2)];  
selectedOp.(5, 3);

It even works with setters which feels weird somehow.

x = (foo: 2)
bar(x) = 3

('bar': 3, 'foo': 2)
1 Like

This is hilarious! :joy: