emdash / udlang

A practical, functional language for stream processing.
GNU Lesser General Public License v3.0
1 stars 0 forks source link

Arbitrary template delegate types #34

Open emdash opened 3 years ago

emdash commented 3 years ago

Allow templates to declare the arguments and return type of their delegates.

This would allow expressing functional patterns like map and fold in the library.

template<T, U> 
fold(accum: U, seq: Iter<T>) -> U
using reducer: (U, T) -> U = {
   yield if (seq.is_empty()) {
     yield accum;
   } else {
     yield fold(reducer(accum, seq.head()), seq.tail());
   }  
}

Used like this:

let sum = fold (0, range(0, 10)) using accum, i {
  yield accum + i;
}

Alternative syntax

let sum = fold (range(0, 10)) {
   yield accum + i;
}

Maybe the latter is short-hand for the former? The former allows re-naming the delegate's arguments, which may be necessary in the event of a collision.

We might have to convert template calls to expressions, and allow them to appear in any expression context. A restricted version could only allow them in let or yield bindings. But by allowing them to be expressions, they can nest.

let sum_squares = fold(0, map(range(1,  $)) {
 yield i * i; 
}) { 
yield accum + i; 
};

Here, partial evaluation is used, making the type of sum_squares equivalent to (Int) -> Int.

This might interact with #33, and I'm not sure which of these I want more. If we can have both, then we could define templates like "map" to take a delegate called reduce, turning the above into:

let map_squares = map (0, range(0, $)) {
   yield i * i;
} reduce {
  yield accum + i;
};