Thread overview
Stack based array language (Uiua)
Sep 30
monkyyy
Oct 05
monkyyy
September 30

https://www.youtube.com/watch?v=iTC1EiX5bM0

soooo new stack-based language but unfortunately in alien runes. I hearing bits and pieces I agree with; like stacks and dups are better than church combinators; but .... alien runes.

discuss?

Is there any project in d inspriped by apl?
Anyone know work arounds for alien runes?
How could you make a small project in d that hacks together a stack meta layer on top of ranges?
Anyone read alien runes? Know good sources for processing them?

October 04
On 9/30/23 18:55, monkyyy wrote:
> How could you make a small project in d that hacks together a stack meta layer on top of ranges?

Generates a lot of template bloat, but you can do this:

```d
import std;

auto dupZeroes(R,T...)(Tuple!(R,T) stack){
    return stack
        .dup
        .dup
        .push(0)
        .equals
        .push(1)
        .add
        .keep
        .flip
        .len
        .take
        ;

}

void main(){
    tuple()
        .push([1,0,2,3,0,4,5,0])
        .dupZeroes
        .push([1,2,3])
        .dupZeroes
        .push([0,3,0,4,5])
        .dupZeroes
        .writeln;
}

alias equals=binary!((a,b)=>a==b);
alias add=binary!((a,b)=>a+b);
alias keep=binary!((a,b)=>zip(a,b).mapArgs!((x,y)=>repeat(x,y)).joiner);
alias len=unary!(x=>x.length);
alias take=std.range.take;
alias take=binary!((a,b)=>a.take(b));

template mapArgs(alias f){ auto mapArgs(R)(R r)=>r.map!(x=>f(x.expand)); }

struct Tuple(T...){
    T expand;
    alias expand this;
    string toString(){
        string r;
        foreach(i,ref x;expand){
            if(i) r~="\n";
            r~=text(x);
        }
        return r;
    }
}
auto tuple(T...)(T args)=>Tuple!T(forward!args);

auto dup(S,T...)(Tuple!(S,T) stack)=>tuple(stack.expand,stack[$-1]);
auto push(S,T...)(Tuple!T stack,S head)=>tuple(stack.expand,head);
auto flip(R,S,T...)(Tuple!(R,S,T) stack)=>tuple(stack[0..$-2],stack[$-1],stack[$-2]);
template apply(alias f,int nargs=-1){
    auto apply(S,T...)(Tuple!(S,T) stack){
        static if(nargs==-1){
            static if(__traits(compiles,f(stack.expand).expand)) return tuple(f(stack.expand).expand);
            else static if(__traits(compiles,f(stack.expand))) return tuple(f(stack.expand));
            else return tuple(stack[0],apply(tuple(stack[1..$])).expand);
        }else{
            static if(__traits(compiles,f(stack[$-nargs..$]).expand)) return tuple(stack[0..$-nargs],f(stack[$-nargs..$]).expand);
            else return tuple(stack[0..$-nargs],f(stack[$-nargs..$]));
        }
    }
}

alias broadcast1(alias f)=(x){
    static if(__traits(compiles,f(x))) return f(x);
    else static if(__traits(compiles,x.map!broadcast1)) return x.map!broadcast1;
    else static assert(0,f(x));
};
alias unary(alias f)=apply!(broadcast1!f,1);
alias broadcast2(alias f)=(x,y){
    static if(__traits(compiles,f(x,y))) return f(x,y);
    else static if(__traits(compiles,x.map!(a=>broadcast2(a,y)))) return x.map!(a=>broadcast2(a,y));
    else static if(__traits(compiles,y.map!(b=>broadcast2(x,b)))) return y.map!(b=>broadcast2(x,b));
    else static if(__traits(compiles,zip(x,y).mapArgs!((a,b)=>broadcast2(a,b)))) return zip(x,y).mapArgs!((a,b)=>broadcast2(a,b));
    else static assert(0,f(x,y));
};
alias binary(alias f)=apply!(broadcast2!f,2);
```
October 05
On Wednesday, 4 October 2023 at 08:36:39 UTC, Timon Gehr wrote:
>

Oooo template code I have trouble reading

Id given up on this; like I thought a stack meta-language would need to know the number of arguments of each function or to generate an ast to mixin something. Whats the base theory of how you modify a stack with only static if compile look ahead?


October 05
On 10/5/23 19:43, monkyyy wrote:
> On Wednesday, 4 October 2023 at 08:36:39 UTC, Timon Gehr wrote:
>>
> 
> Oooo template code I have trouble reading
> 
> Id given up on this; like I thought a stack meta-language would need to know the number of arguments of each function or to generate an ast to mixin something.

Well, technically all the functions that are actually called in my example do specify the number of arguments on the stack (e.g. `unary` and `binary` templates and the examples below), but that's mainly for better error messages.

```d
auto dup(S,T...)(Tuple!(S,T) stack)=>tuple(stack.expand,stack[$-1]);
auto push(S,T...)(Tuple!T stack,S head)=>tuple(stack.expand,head);
auto flip(R,S,T...)(Tuple!(R,S,T) stack)=>tuple(stack[0..$-2],stack[$-1],stack[$-2]);
```

Otherwise, I just use a tuple as my stack. If you don't provide the number of arguments to `apply`, it will try to call the function with all suffixes of the tuple and call the longest one. Then there's some improvised broadcasting logic (may not be the sanest behavior imaginable, didn't do much testing) in the `unary` and `binary` templates so that ranges can combine with literals.

> Whats the base theory of how you modify a stack with only static if compile look ahead?
> 
> 

I guess you are asking about this part:

```d
auto apply(S,T...)(Tuple!(S,T) stack){
    static if(__traits(compiles,f(stack.expand).expand))
        return tuple(f(stack.expand).expand);
    else static if(__traits(compiles,f(stack.expand)))
        return tuple(f(stack.expand));
    else return tuple(stack[0],apply(tuple(stack[1..$])).expand);
}
```

First I check whether `f` returns something that can be expanded when called on the entire stack, this is so functions that return multiple results in a tuple will push multiple results on the stack. The second case is just to also support the case where `f` just returns a single result when called on the entire stack. If calling on the entire stack does not work, I preserve the first argument on the stack and recurse on the remaining part of the stack.

Though in practice I think I have only used this branch of apply in the code I pasted:

auto apply(S,T...)(Tuple!(S,T) stack){
    static if(__traits(compiles,f(stack[$-nargs..$]).expand))
        return tuple(stack[0..$-nargs],f(stack[$-nargs..$]).expand);
    else return tuple(stack[0..$-nargs],f(stack[$-nargs..$]));
}

I.e., here I pass `nargs` explicitly and it just picks the correct suffix to call, expanding it into the stack if possible.