Your very own "for" instruction, redux

2

0

Inspired by Sygmei's question, I'm interested in finding out what languages can "do this properly".

Your task is to write a "for loop" function / macro / instruction. The arguments should be:

  • an initializer
  • a test
  • an increment
  • a body

All of these are "pieces of code" and should be able to access variables in the context of the call. The body should be able to include multiple statements.

The aim is to have the fewest lexical tokens excluding comments, except that #define and friends (using a dumb preprocessor) are worth 50, and eval and friends (taking a string argument) are worth 100. Feel free to make your code readable with comments, whitespace and meaningful names.

You should include a "test harness" which is not counted towards length.

The C version definitely won't win:

// the do {...} while (0) idiom enables a code block to be a single C statement, so it can safely be followed by a semicolon
#define my_for(init, test, inc, body) do {  \
    init; \
    while (test) { \
        body; \
        inc; \
    } \
} while (0)

// test harness:
#include <stdio.h>

main()
{
    int i, total;
    my_for((i=1, total=0), i<=3, ++i, {printf("%d\n", i); total=total+i;});
    printf("total: %d\n", total);
}

Edit to add: the meaning of "lexical token" depends on your language. Here's how the scoring breaks down for my C version:

//[...]: 0
#define: 1 occurrence, 50 points
my_for: 1
(: 3
init: 2
,: 3
test: 2
inc: 2
body: 2
): 3
do: 1
{: 2
\: 6
;: 3
while: 2
}: 2
0: 1

TOTAL: 85

Hugh Allen

Posted 2017-01-27T03:26:03.043

Reputation: 129

Question was closed 2017-01-29T20:24:16.140

3Unclear to me: scoring. For example how would your c reference be scored? – Digital Trauma – 2017-01-27T04:42:56.023

I was actually going to do this challenge, but I ran into a fair number of difficulties in laying it out. I hope someone posts a well explained version; preferably normal code golf. – Carcigenicate – 2017-01-27T16:18:28.540

@DigitalTrauma does my edit clarify it sufficiently? If so how can I get the question re-opened? I can't tag all the on-hold-voters in this comment – Hugh Allen – 2017-01-28T02:40:36.563

The C scoring only makes it clear for C programs. It's very hard to define "tokens" for a wide range of languages. You either have to give up on the idea, or only allow a narrow range of languages (which is a whole different can of worms). – Mego – 2017-01-28T04:29:02.537

>

  • Can it be a lambda (anonymous function), or does it have to be a named function? 2) Is it okay to use the language's built-in for loop syntax in the implementation?
  • < – smls – 2017-01-28T22:28:35.440

    @Mego: Can you give an example where it is be hard to identify tokens? If it's just edge cases, can't they be resolved by asking the task author on a case by case basis? – smls – 2017-01-28T22:32:45.640

    @smls Asking the OP for every unclear case isn't reasonable. The rules need to be static and objective, not constantly being added to because edge cases come up that require the OP's discretion. – Mego – 2017-01-28T22:34:01.643

    Name suggestion: My little For loop (sorry, mlp reference kek) – Matthew Roh – 2017-01-29T00:19:59.373

    @smls 1. an anonymous function is fine. 2. reusing the builtin for-loop syntax is fine; reusing the builtin for-loop implementation is cheating. – Hugh Allen – 2017-01-29T02:04:12.433

    I'm sorry, but this is still very confusing to me; in particular, it seems like we need judges to tell when something in a language counts as an eval or "dumb macro"; as in your comment in the TCL answer (which by no means is apparent to me reading your description here), or possibly how to judge the use of FORTH words. Heck, I'm not even sure whether a traditional C preprocessor metaprogramming EVAL counts as a macro, or an eval, or both, or neither if using CPP as the language (despite your use of CPP in C as an example of dumb macros). – H Walters – 2017-01-29T02:50:13.343

    @HWalters re TCL answer: uplevel is like eval because it takes a string argument, and contains an interpreter for the language. Re CPP: I'm penalising C-style macros partly so we don't have to worry about it (and partly because they suck) – Hugh Allen – 2017-01-29T04:09:01.803

    @HWalters just read it as "don't use these" – Hugh Allen – 2017-01-29T04:44:17.837

    Okay, no chat, so cleaning up clutter, but I'll leave it at this. (1) I really think you need to define "dumb preprocessor", and clearly state whether this involves the same language level parsing or not. (2) You also need to specify what counts as "eval" here; everything is a string until parsed, so this only becomes conflated with interpreted languages. (3) You might have to worry about CPP; I can pretty confidently say it won't win, but unless you forbid it it's not up to you whether there's a submission in it. Hacking in CPP is actually a personal hobby of mine. – H Walters – 2017-01-29T05:28:22.820

    Answers

    2

    Python, 11 26 tokens:

    def f(n, t, i, l):
        n()
        while t():
            l()
            i()
    

    This is my first time doing , so forgive me if I got the token counting wrong.

    EDIT: Hugh Allen informed me that I got the token counting wrong.

    Esolanging Fruit

    Posted 2017-01-27T03:26:03.043

    Reputation: 13 542

    The thing is, [tag:atomic-code-golf] doesn't actually exist. – feersum – 2017-01-27T06:17:01.833

    5@feersum It has 44 questions. How does it not exist? – Post Rock Garf Hunter – 2017-01-27T19:36:32.900

    That's a nice answer, but it's more than 11 tokens! See my edit for clarification (I hope) – Hugh Allen – 2017-01-28T02:41:56.640

    I can't see your edit. Could you explain to me why it's more than 11 tokens? – Esolanging Fruit – 2017-01-28T06:05:31.380

    All of those punctuation characters are tokens (though sometimes two punctuation chars can be a single token, eg. <=) – Hugh Allen – 2017-01-28T08:43:24.283

    1@HughAllen So 26 tokens? – Esolanging Fruit – 2017-01-28T19:27:44.983

    @Challenger5 yes, 26 seems correct to me – Hugh Allen – 2017-01-29T02:05:23.430

    1

    Perl 6, 24 tokens

    sub my-for (&init, &test, &inc, &body) {
        init;
        while (test) { body; inc }
    }
    

    Tokens:

    while   1   keyword
    sub     1   keyword
    my-for  1   function name (declaration)
    &init   1   function parameter (declaration)
    &test   1   function parameter (declaration)
    &inc    1   function parameter (declaration)
    &body   1   function parameter (declaration)
    init    1   function name (implicit call)
    test    1   function name (implicit call)
    inc     1   function name (implicit call)
    body    1   function name (implicit call)
    ,       3   parameter list separator
    ;       2   statement separator
    {       2   block opener
    }       2   block closer
    (       2   parameter list opener
    )       2   parameter list closer
    

    Test:

    my ($i, $total);
    my-for {$i=1; $total=0}, {$i <= 3}, {++$i}, {
        say $i;
        $total = $total + $i;
    }
    say "total: $total";
    

    smls

    Posted 2017-01-27T03:26:03.043

    Reputation: 4 352

    0

    tcl, could I say 0 due to point 1.?

    If the question was "how many ways your language allow you to do it", tcl would certainly score a good amount.

    1. for

    The language's normal for works this way; it should me noted that tcl has no keywords, so for works exactly like a function (side note: its behaviour can even be redefined!). Then, there is no need to implement it:

    for {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
    puts total:\ $total
    
    1. proc

    Implement a function, strictly according to the question.

    2.1. uplevel

    The uplevel 1 will execute its contents 1 level up in the call stack, to allow there the access to the variables of the for input; otherwise we could not access $total, because it would be not defined.

    proc F {s t i b} {uplevel 1 [list for $s $t $i $b]}
    F {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
    puts total:\ $total
    

    2.2. tailcall

    From tailcall documentation: "The tailcall command replaces the currently executing procedure, lambda application, or method with another command."

    proc P args {tailcall for {*}$args}
    P {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
    puts total:\ $total
    
    1. interp alias

    You can say to one of the interpreters currently existing on interpreters tree that a command has an alias. I didn't create any interpreter, so I am interested on the tree's root interpreter, which path is an empty string, represented by {}. The following line means: "Create the alias R on the root interpreter, which will re-route calls to it to for on the root interpreter.

    interp alias {} R {} for
    R {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
    puts total:\ $total
    
    1. set

    You can define a var that will have the same value has for command:

    set S for
    $S {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
    puts total:\ $total
    
    1. rename

    You can change the name of the function. Note: From now on, you can not call for directly again! Now you must always call f, until you rename it back!

    rename for f
    f {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
    puts total:\ $total
    

    demo

    sergiol

    Posted 2017-01-27T03:26:03.043

    Reputation: 3 055

    >

  • Almost every language has a "for" loop; giving the builtin one is definitely cheating.
  • uplevel is like eval and is worth 100 points!
  • < – Hugh Allen – 2017-01-29T01:59:47.467