Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get a lot of macros early in the examples, by cheating #324

Open
masak opened this issue Jun 28, 2018 · 1 comment
Open

Get a lot of macros early in the examples, by cheating #324

masak opened this issue Jun 28, 2018 · 1 comment

Comments

@masak
Copy link
Owner

masak commented Jun 28, 2018

Thinking out loud here a bit. Here's examples/99-bottles.007:

func verse(n) {
    func plural(n, thing) {
        if n == 1 { 
            return n ~ " " ~ thing;
        }   
        else {
            return n ~ " " ~ thing ~ "s";
        }   
    }   

    say(plural(n + 1, "bottle") ~ " of beer on the wall,");
    say(plural(n + 1, "bottle") ~ " of beer.");
    say("Take one down, pass it around,");
    say(plural(n, "bottle") ~ " of beer on the wall...");
}   

for (^99).reverse() -> beerCount {
    verse(beerCount);
    if beerCount > 0 { 
        say("");
    }   
}   

Here's how I would like to write it:

import * from syntax.op.conditional;
import * from syntax.str.template;

func plural(n, thing) {
    `${n} ${thing}${n == 1 ?? "" !! "s"}`;
}

for (^99).reverse() -> n {
    say(plural(n + 1, "bottle"), " of beer on the wall,");
    say(plural(n + 1, "bottle"), " of beer.");
    say("Take one down, pass it around,");
    say(plural(n, "bottle"), " of beer on the wall...");
    
    if n > 0 {
        say("");
    }   
}   

Here's examples/euclid-gcd.007:

macro swap(a, b) {
    return quasi {
        my t = {{{a}}};
        {{{a}}} = {{{b}}};
        {{{b}}} = t;
    };
}

func gcd(a, b) {
    if b {
        return gcd(b, a % b);
    }
    return a.abs();
}

my bigger = +prompt("Enter the bigger integer: ");
my smaller = +prompt("Enter the smaller integer: ");

if bigger < smaller {
    swap(bigger, smaller);
}

say();
say("Greatest common denominator: ", gcd(bigger, smaller));

And here's how I would like to write it:

import * from syntax.op.conditional;
import * from syntax.op.assign;
import * from syntax.expr.destructure;

func gcd(a, b) {
    b ?? gcd(b, a % b) !! a.abs();
}

my bigger = +prompt("Enter the bigger integer: ");
my smaller = +prompt("Enter the smaller integer: ");

[bigger, smaller].=sort();
    
say("");
say("Greatest common denominator: ", gcd(bigger, smaller));

examples/fizzbuzz.007:

my n = 1;
while n <= 100 {
    if n %% 15 {
        say("FizzBuzz");
    }
    else if n %% 3 {
        say("Fizz");
    }
    else if n %% 5 {
        say("Buzz");
    }
    else {
        say(n);
    }
    n = n + 1;
}   

And my ideal:

import * from range;
import * from syntax.op.conditional;

for 1 .. 100 -> n {
    say(n %% 15
        ?? "FizzBuzz"
        !! n %% 3
            ?? "Fizz"
            !! n %% 5
                ?? "Buzz"
                !! n
    );
}

examples/quicksort.007:

func quicksort(array) {
    if array.size() > 1 {
        my pivot = array[0];
        my less = quicksort(array.filter(func (e) { return e < pivot }));
        my equal = array.filter(func (e) { return e == pivot });
        my greater = quicksort(array.filter(func (e) { return e > pivot }));
        array = less.concat(equal.concat(greater));
    }
    return array;
}

my unsorted = (^20).shuffle();
say("Unsorted: " ~ unsorted);
say("Sorting...");
my sorted = quicksort(unsorted);
say("Sorted: " ~ sorted);

And how I think it ought to look:

import * from syntax.func.arrow.p6;
import * from syntax.array.spread;

func quicksort(array) {
    if array.size() > 1 {
        my pivot = array[0];
        my less = quicksort(array.filter(-> e { return e < pivot }));
        my equal = array.filter(-> e { return e == pivot }); 
        my greater = quicksort(array.filter(-> e { return e > pivot }));
        array = [...less, ...equal, ...greater];
    } 
    return array;
}   

my unsorted = (^20).shuffle();
say("Unsorted: ", unsorted);
say("Sorting...");
my sorted = quicksort(unsorted);
say("Sorted: ", sorted);

examples/quine.007:

my lines = [
    "my lines = [",
    "    ",
    "];",
    "for lines -> line {",
    "    if line.chars() == 4 {",
    "        for lines -> quotedLine {",
    "            say(line ~ 34.chr() ~ quotedLine ~ 34.chr() ~ 44.chr());",
    "        }",
    "    }",
    "    else {",
    "        say(line);",
    "    }",
    "}",
];
for lines -> line {
    if line.chars() == 4 {
        for lines -> quotedLine {
            say(line ~ 34.chr() ~ quotedLine ~ 34.chr() ~ 44.chr());
        }
    }
    else {
        say(line);
    }
}

And how I'd prefer to write it:

import * from syntax.str.template;

my program = `import * from syntax.str.template;

my program = ☃;

say(program.subst("☃", 96.chr() ~ program ~ 96.chr()));
`;

say(program.subst("☃", 96.chr() ~ program ~ 96.chr()));

The modules syntax.op.conditional, syntax.str.template, syntax.array.spread, swap, range and syntax.func.arrow.p6 don't have to be actual 007 modules in the beginning for us to have good use for them. I suggest we, at least in a branch, make all of the examples work in the above suggested forms, simply by "mocking" what those modules will do.

That is, the actual implementation will live in _007::Parser::Syntax, with enough support from runtime values etc. Not how we want it in the long run... but probably a very interesting way to get early feedback from those things. -Ofun and all that.

@masak
Copy link
Owner Author

masak commented Feb 9, 2019

Since I liked the result of #401 (comment) so much, I went ahead and edited the OP above so it has those module names.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant