Escaping commas in macro output - macros

I am trying to write a macro which enables me to transform
(a, b, c, d) to (a, a + b, a + b + c, a + b + c + d), etc. Here is what I have got so far:
macro_rules! pascal_next {
($x: expr) => ($x);
($x: expr, $y: expr) => (
($x, $x + $y)
);
($x: expr, $y: expr, $($rest: expr),+) => (
($x, pascal_next!(
$x + $y, $($rest),+
)
)
);
}
However, there is a problem that it would actually output (a, (a + b, (a + b + c, a + b + c +d))). The origin is that the second matching rule ($x: expr, $y: expr) => (($x, $x + $y));, produces an extra bracket, so that there would be nested brackets. If I don't put a bracket outside, I would get the error error:
unexpected token: ,
So is it possible to output a comma , in Rust macros?

No; the result of a macro must be a complete grammar construct like an expression or an item. You absolutely cannot have random bits of syntax like a comma or a closing brace.
You can get around this by simply not outputting anything until you have a complete, final expression. Behold!
#![feature(trace_macros)]
macro_rules! pascal_impl {
/*
The input to this macro takes the following form:
```ignore
(
// The current output accumulator.
($($out:tt)*);
// The current additive prefix.
$prefix:expr;
// The remaining, comma-terminated elements.
...
)
```
*/
/*
Termination condition: there is no input left. As
such, dump the output.
*/
(
$out:expr;
$_prefix:expr;
) => {
$out
};
/*
Otherwise, we have more to scrape!
*/
(
($($out:tt)*);
$prefix:expr;
$e:expr, $($rest:tt)*
) => {
pascal_impl!(
($($out)* $prefix+$e,);
$prefix+$e;
$($rest)*
)
};
}
macro_rules! pascal {
($($es:expr),+) => { pascal_impl!((); 0; $($es),+,) };
}
trace_macros!(true);
fn main() {
println!("{:?}", pascal!(1, 2, 3, 4));
}
Note: To use this on a stable compiler, you will need to delete the #![feature(trace_macros)] and trace_macros!(true); lines. Everything else should be fine.
What this does is it recursively munches away at the input, passing the partial (and potentially semantically invalid) output as input to the next level of recursion. This lets us build up an "open list", which we couldn't otherwise do.
Then, once we're out of input, we just re-interpret our partial output as a complete expression and... done.
The reason I including the tracing stuff is so I could show you what it looks like as it runs:
pascal! { 1 , 2 , 3 , 4 }
pascal_impl! { ( ) ; 0 ; 1 , 2 , 3 , 4 , }
pascal_impl! { ( 0 + 1 , ) ; 0 + 1 ; 2 , 3 , 4 , }
pascal_impl! { ( 0 + 1 , 0 + 1 + 2 , ) ; 0 + 1 + 2 ; 3 , 4 , }
pascal_impl! { ( 0 + 1 , 0 + 1 + 2 , 0 + 1 + 2 + 3 , ) ; 0 + 1 + 2 + 3 ; 4 , }
pascal_impl! { ( 0 + 1 , 0 + 1 + 2 , 0 + 1 + 2 + 3 , 0 + 1 + 2 + 3 + 4 , ) ; 0 + 1 + 2 + 3 + 4 ; }
And the output is:
(1, 3, 6, 10)
One thing to be aware of: large numbers of un-annotated integer literals can cause a dramatic increase in compile times. If this happens, you can solve it by simply annotating all of your integer literals (like 1i32).

Related

In Raku, how does one calculate the sum of positive divisors from a prime factorization?

In Raku, given a list of pairs (2 => 3, 3 => 2, 5 => 1, 7 => 4) ( representing the prime factorization of n = 2 3 · 3 2 · 5 1 · 7 4 ), how does construct a Raku expression for σ(n) = ( 2 0 + 2 1 + 2 2 + 2 3 ) · ( 3 0 + 3 1 + 3 2 ) · ( 5 0 + 5 1 ) · ( 7 0 + 7 1 + 7 2 + 7 3 + 7 4 ) ?
sub MAIN()
{
my $pairList = (2 => 3, 3 => 2, 5 => 1, 7 => 4) ;
say '$pairList' ;
say $pairList ;
say $pairList.WHAT ;
# Goal:
# from $pairList,
# the product (1 + 2 + 4 + 8) * (1 + 3 + 9) * (1 + 5) * (1 + 7 + 49 + 343 + 2401)
# = sigma ( 2^3 * 3^2 * 5^1 * 7^4 )
} # end sub MAIN
Update 1
Based upon the answer of #raiph, the following program breaks the overall process into stages for the newcomer to Raku (such as me) …
sub MAIN()
{
my $pairList = (2 => 3, 3 => 2, 5 => 1, 7 => 4) ;
say '$pairList' ;
say $pairList ;
say $pairList.WHAT ;
# Goal:
# from $pairList,
# the product (1 + 2 + 4 + 8) * (1 + 3 + 9) * (1 + 5) * (1 + 7 + 49 + 343 + 2401)
# the product (15) * (13) * (6) * (2801)
# sigma ( 2^3 * 3^2 * 5^1 * 7^4 )
# 3277170
# Stage 1 : ((1 2 4 8) (1 3 9) (1 5) (1 7 49 343 2401))
my $stage1 = $pairList.map: { (.key ** (my $++)) xx (.value + 1) } ;
say '$stage1 : lists of powers' ;
say $stage1 ;
say $stage1.WHAT ;
# Stage 2 : ((1 + 2 + 4 + 8) (1 + 3 + 9) (1 + 5) (1 + 7 + 49 + 343 + 2401))
my $stage2 = $stage1.map: { sum $_ } ;
say '$stage2 : sum each list' ;
say $stage2 ;
say $stage2.WHAT ;
# Stage 3 : (1 + 2 + 4 + 8) * (1 + 3 + 9) * (1 + 5) * (1 + 7 + 49 + 343 + 2401)
my $stage3 = $stage2.reduce( &infix:<*> ) ;
say '$stage3 : product of list elements' ;
say $stage3 ;
say $stage3.WHAT ;
} # end sub MAIN
A related post appears on Mathematics Stack Exchange.
Update 2
My original motivation had been to calculate aliquot sum s(n) = σ(n) - n. I found that prime factorization of each n is not necessary and seems inefficient. Raku and C++ programs calculating s(n) for n = 0 … 10 6 follow …
Raku
sub MAIN()
{
constant $limit = 1_000_000 ;
my #s of Int = ( 1 xx ($limit + 1) ) ;
#s[0] = 0 ;
#s[1] = 0 ;
loop ( my $column = 2; $column <= ($limit + 1) div 2; $column++ )
{
loop ( my $row = (2 * $column); $row <= $limit; $row += $column )
{
#s[$row] += $column ;
} # end loop $row
} # end loop $column
say "s(", $limit, ") = ", #s[$limit] ; # s(1000000) = 1480437
} # end sub MAIN
C++
(Observed to execute significantly faster than Raku)
#include <iostream>
#include <vector>
using namespace std ;
int main ( void )
{
const int LIMIT = 1000000 ;
vector<int> s ( (LIMIT + 1), 1 ) ;
s[0] = 0 ;
s[1] = 0 ;
for ( int col = 2 ; col <= (LIMIT + 1) / 2 ; col++ )
for ( int row = (2 * col) ; row <= LIMIT ; row += col )
s[row] += col ;
cout << "s(" << LIMIT << ") = " << s[LIMIT] << endl ; // s(1000000) = 1480437
} // end function main
There'll be bazillions of ways. I've ignored algorithmic efficiency. The first thing I wrote:
say [*] (2 => 3, 3 => 2, 5 => 1, 7 => 4) .map: { sum .key ** my $++ xx .value + 1 }
displays:
3277170
Explanation
1 say
2 [*] # `[op]` is a reduction. `[*] 6, 8, 9` is `432`.
3 (2 => 3, 3 => 2, 5 => 1, 7 => 4)
4 .map:
5 {
6 sum
7 .key # `.key` of `2 => 3` is `2`.
8 **
9 my # `my` resets `$` for each call of enclosing `{...}`
10 $++ # `$++` integer increments from `0` per thunk evaluation.
11 xx # `L xx R` forms list from `L` thunk evaluated `R` times
12 .value + 1
13 }
It is unlikely that Raku is ever going to be faster than C++ for that kind of operation. It is still early in its life and there are lots of optimizations to be gained, but raw processing speed is not where it shines.
If you are trying to find the aliquot sum for all of the numbers in a continuous range then prime factorization is certainly less efficient than the method you arrived at. Sort of an inverse Sieve of Eratosthenes. There are a few things you could change to make it faster, though still probably much slower than C++
About twice as fast on my system:
constant $limit = 1_000_000;
my #s = 0,0;
#s.append: 1 xx $limit;
(2 .. $limit/2).race.map: -> $column {
loop ( my $row = (2 * $column); $row <= $limit; $row += $column ) {
#s[$row] += $column ;
}
}
say "s(", $limit, ") = ", #s[$limit] ; # s(1000000) = 1480437
Where the prime factorization method really shines is for finding arbitrary aliquot sums.
This produces an answer in fractions of a second when the inverse sieve would likely take hours. Using the Prime::Factor module: from the Raku ecosystem
use Prime::Factor;
say "s(", 2**97-1, ") = ", (2**97-1).&proper-divisors.sum;
# s(158456325028528675187087900671) = 13842607235828485645777841

Split an array based on value

This is my first question here, so sorry if I make any mistakes posting this.
I'm trying to split an array based on its values. Basically I want to create two arrays whose values are as close to the average as possible. I managed to do this with this code:
function Sum($v) {
[Linq.Enumerable]::Sum([int64[]]$v)
}
$arr = 0..9 | % {get-random -min 1 -max 10}
"ARRAY:" + $arr
"SUM: " + (sum $arr)
"AVG: " + (sum $arr)/2
# start of the code that matters
$wavg = (sum $arr)/2
foreach ($i in (0..($arr.Count-1))) {
$wavg -= $arr[$i]
if ($wavg -le 0) {
$i-=(-$wavg -gt $arr[$i]/2);break
}
}
"SPLIT INDEX: " + $i
"ARR1: " + $arr[0..$i] + " (" + $(sum $arr[0..$i]) + ")"
"ARR2: " + $arr[($i+1)..$arr.Count] + " (" + $(sum $arr[($i+1)..$arr.Count]) + ")"
The reason my foreach is structured this way is because in my actual code the values are in an index hash and are accessed as $index[$arr[$i]].
This means that the resulting two arrays could be of unequal size (it would be easy if I could just split the array in half). Sample output of my code to demonstrate this:
ARRAY: 5 3 6 3 2 3 6 3 1 3
SUM: 35
AVG: 17.5
SPLIT INDEX: 3
ARR1: 5 3 6 3 (17)
ARR2: 2 3 6 3 1 3 (18)
The code works as is, but I feel it could be done in a more elegant and speedier way. Because I need to execute this code a few thousand times in my script I want it to be as fast as possible.

Recursive function in XCode Playground (Swift)

I'm learning recursive functions in Swift, and I did the following:
func recursive(i: Int) -> Int {
if i == 1 {
return 1
} else if i >= 2 {
return recursive(i: i - 1) + 1
}
return 0
}
I couldn't figure out why the function above is not working. I've tested it by doing the below doing print(recursive(10)), which gives me an output of 10. I expected the output to be 1. Can anyone help me with this? Thank you in advance.
I'm using Playgrounds on XCode 8.3.
When you do this:
recursive(i: i - 1) + 1
… then you are in effect decrementing i and then incrementing it again. That cancels out and you arrive at i again.
Let's write down what calculation would be done for i = 3:
(3 - 1) + 1 = ((2 - 1) + 1) + 1 = (((1) + 1) + 1) = 3
This is a perfect example of printing numbers without using any loop.
The recursive functions are very useful to handle such cases.
func printCount( count : inout Int , limit : Int) {
print(count, terminator: " ")
count += 1
if count > limit {
return
}
printCount(count: &count , limit: limit)
}
var count = 11
let limit = 20
printCount(count: &count , limit: limit)
Output : 11 12 13 14 15 16 17 18 19 20

Powershell is there an easy way to covert an int 5 to a string five or 68 to sixty eight?

I'm trying to figure out if there is an easy way to convert numbers into words take 9 and convert it to nine.
There is an excellent library for .NET called Humanizer that can do exactly this. I haven't tried this yet, but it looks like there is a PowerShell wrapper for it. I suspect this will do exactly what you need.
This has been asked about .NET/C#; you could put this in a class and use Add-Type in powershell to make this work.
.NET convert number to string representation (1 to one, 2 to two, etc...)
Maybe something like this (untested):
$class = #"
public class Num2Word
{
public static string NumberToText( int n)
{
if ( n < 0 )
return "Minus " + NumberToText(-n);
else if ( n == 0 )
return "";
else if ( n <= 19 )
return new string[] {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight",
"Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen",
"Seventeen", "Eighteen", "Nineteen"}[n-1] + " ";
else if ( n <= 99 )
return new string[] {"Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy",
"Eighty", "Ninety"}[n / 10 - 2] + " " + NumberToText(n % 10);
else if ( n <= 199 )
return "One Hundred " + NumberToText(n % 100);
else if ( n <= 999 )
return NumberToText(n / 100) + "Hundreds " + NumberToText(n % 100);
else if ( n <= 1999 )
return "One Thousand " + NumberToText(n % 1000);
else if ( n <= 999999 )
return NumberToText(n / 1000) + "Thousands " + NumberToText(n % 1000);
else if ( n <= 1999999 )
return "One Million " + NumberToText(n % 1000000);
else if ( n <= 999999999)
return NumberToText(n / 1000000) + "Millions " + NumberToText(n % 1000000);
else if ( n <= 1999999999 )
return "One Billion " + NumberToText(n % 1000000000);
else
return NumberToText(n / 1000000000) + "Billions " + NumberToText(n % 1000000000);
}
}
#"
Add-Type -TypeDefinition $class
[Num2Word]::NumberToText(555)
There's no reason you couldn't write this as pure powershell, but this was already written!

Coffeescript - Improve algorithm for increasing grouping

The code below works but I am wondering if there is a better way that maybe uses some of the features of coffeescript that I am unfamiliar with.
The problem is this, I need to page items but the paging increases each time.
If I take the number 20 for example, it would create the following pages:
1 - 3
4 - 7
8 - 15
16 - 20
I have the following test and code which does pass:
module 'Remainder',
setup: ->
#remainder = 20
test 'splits remainder incrementally', ->
parts = #remainder.increasingSplit()
equal parts[0], '1 - 3', ''
equal parts[1], '4 - 7', ''
equal parts[2], '8 - 15', ''
equal parts[3], '16 - 20', ''
Number.prototype.increasingSplit = ->
start = 1
nextSplit = 3
parts = []
finished = false
while !finished
if nextSplit > #
parts.push "#{start} - #{#}"
break
parts.push "#{start} - #{nextSplit}"
start = nextSplit + 1
nextSplit = nextSplit * 2 + 1
parts
Without changing the algorithm too much, you can try this:
Number::increasingSplit = ->
start = 1
nextSplit = 3
parts = []
while start <= #
parts.push "#{start} - #{Math.min nextSplit, #}"
start = nextSplit + 1
nextSplit = nextSplit * 2 + 1
parts
The changes were:
replacing .prototype with ::,
removing of the finished variable (which was not being used effectively because the break anyway) and the break altogether and changing the condition to start <= #,
using only one parts.push <part>, with the minimum between nextSplit and # as the top.
Also, i'd advice against extending the Number prototype in this case. Extending the prototype of primitive types can sometimes cause weird problems, like:
Number::isFour = -> # is 4
console.log 4.isFour() # -> false
That happens because inside that function # will be a Number object instead of a primitive number, thus making the === 4 comparison always fail. That would not happen if you define isFour as a standalone function:
isFour = (n) -> n is 4
console.log isFour 4 # -> true
So, i'd prefer this version of incrasingSplit:
increasingSplit = (n) ->
start = 1
nextSplit = 3
parts = []
while start <= n
parts.push "#{start} - #{Math.min nextSplit, n}"
start = nextSplit + 1
nextSplit = nextSplit * 2 + 1
parts
Finally, if you don't mind recursion, you can go with a more FP-style algorithm :)
increasingSplit = (n, start = 1, nextSplit = 3) ->
if start > n
[]
else
part = "#{start} - #{Math.min nextSplit, n}"
rest = increasingSplit n, nextSplit + 1, nextSplit * 2 + 1
[part, rest...]