Hello.
I was wondering if there was a way to handle a function thus:
function _init() a=1 b=2 c=3 showargs(a,b,c) end function showargs(p) for i in all(p) do print(argval(i)) end end |
Results would be:
1 2 3 |
Thought I would add this little query too.
How do you properly copy one array to another without this happening ?
a={1,2,3} b=a a[1]=5 ?b[1] |
Result is 5.
For the first, you'd probably have to do this to get what you want:
p={a=1, b=2, c=3} showargs(p) ... |
For the second, tables are passed by reference, not by value. So if you want a copy of it, you have to make it yourself. Here's a good reference on that:
hi @MBoffin. Thanks for the copy table. That should work. As for the latter, I tried this code with no output appearing:
p={a=1,b=2,c=3} for i in all(p) do print(i) end |
. . .
Nope, the copy array function is also not working. Isolated the code:
function table.clone(org) return {table.unpack(org)} end |
@dw817 You probably want pairs instead of all in the first thing:
for key,val in pairs(p) do print(key.."="..val) end |
Note that this won't necessarily output in the same order they appear in the assignment statement.
As to the first, you won't get anything via all()
because they are named values, not indexed values. If you want to loop through them, you'd need to do p={1,2,3}
instead of naming them a
, b
, and c
.
As to the second, the code from that reference won't translate directly to PICO-8, just the basic ideas presented there. You'd have to translate it to features that PICO-8 implements (of which type()
is one, at least).
Hi @MBoffin:
Basic idea is not gonna be at a level I'd understand. I can code in BASIC and variants of (is why I'm here in Pico-8).
I think that works ! Interesting stuff !
cls() p={a=1,b=2,c=3} for key,val in pairs(p) do print(key.."="..val) end |
One problem is when you run it - it gets random results ? Is there a way to force it to display sequentially - or even in reverse ?
@dw817 none that I know of, at least not directly. The Lua docs say the order is unspecified and should not be relied upon to be in any given order, or even repeat the same order in subsequent runs. I wouldn't be surprised if someone here has written some code to do this though. You'd probably have to keep track of either the insertion index or the keys separately in a different table, then somehow use that to iterate over p to get what you want, but it's not something I've ever tried myself.
Something to work on then ... thanks guys, I'll see what I can do !
I think part of the issue is that unless they're in a sequence, there's no one correct order for them to go in. You would have to supply that. If you know the order beforehand, though, you could do something like this:
cls() p={a=1,b=2,c=3} seq="abc" for i in all(split(seq,"",false)) do print(p[i]) end |
use varargs in the definition of showargs, then convert varargs to a table to be able to use all:
-- example call: showargs(a,b,c) function showargs(...) for arg in all({...}) do print(arg) end end |
Both are quite interesting, @merwok and @kimiyoribaka.
Kimi, yours to determine sort order of an array by a string.
Merwok, yours to work with any number of arguments.
Both quite helpful, definitely I can learn from these, thank you !
Kimi, yours is interesting in that apparently you can convert a string back to a true named array, is this the case ?
cls() p={a=11,b=21,c=31} seq="abc" for i in all(split(seq,"",false)) do print(p[i]) end |
Would it be possible to have.
a=17 seq="45*(23+a)" p=calcargs(seq) print(p) |
PICO-8 supports passing an arbitrary number of function arguments which you can cast into an array and loop over.
Here's an example that shows what you were looking to do:
function showargs( ... ) local args={...} for k in all(args) do print( k ) end end showargs( 1,2,3,4,5 ) -- will print 1 through 5, each on a line |
As for copying tables instead of just making a new reference, you basically need to create a new table and copy the keys/values or indexed elements over to the new table. How to accomplish this kind of depends on whether the table is indexed by numbers or keys. If they are indexed by numbers, you can use ipairs and it will be faster and ignore non-integer keys, but usually you'll want to index by keys, since indexed-by-numbers tables will work that way, too.
Depending on your use case, you might have to do a "deep" copy or a "shallow" copy. For instance, if you have a table of subtables, and you do a "shallow" copy, the top-level table will be its own thing, but the subtables will be shared. Sometimes you want deep copies and sometimes you want shallow copies, so there's not really a "one size fits all" table-copying solution, but here's examples of both:
cls() function copy( tab ) local cp = {} for k,v in pairs( tab ) do cp[k] = v end return cp end a = {1,2,3} b = copy(a) b[1] = 99 print("a[1]="..a[1]) print("b[1]="..b[1]) a = {{1,2,3},{1,2,3}} b = copy(a) b[1][1] = 99 print("a[1][1]="..a[1][1]) print("b[1][1]="..b[1][1]) function deepcopy( tab ) local cp = {} for k,v in pairs( tab ) do if type(v)=="table" then cp[k] = deepcopy( v ) else cp[k] = v end end return cp end c = {{1,2,3},{1,2,3}} d = deepcopy(a) d[1][1] = 99 print("c[1][1]="..c[1][1]) print("d[1][1]="..d[1][1]) |
Hi @nephilim:
Yep that will work. I think I understand the ALL and PAIRS function at this. What I was just wondering if from seeing above you can actually do a calculation from a string now.
I know back on the TRS-80 you could have:
CLS INPUT A PRINT A |
You run the code, you could type: 2*(3+4)
and get back 14
It seems like you can since you can call a variable inside a definition like { and }.
What my code example does is store names that are 1 character in length in a string and use those names to access the table value. The parameters to split()
are saying that there aren't any delimiters (which causes the names to be length 1) and to not try to convert any of the characters to numbers.
a=17 seq="45*(23+a)" p=calcargs(seq) print(p) |
This looks like a case where you'd be executing an arbitrary string of code at run-time. There's functions in normal Lua to do that, but I don't think there's any functions for that in Pico-8, likely because it's a thing console have historically not liked. You can certainly do it manually, but that'd get messy really quickly unless you use delimiters.
For example, using this string would be easier: "45,*,(,23,+,a,)". Then you could pass "," to split()
and get back a table that already separates each portion as tokens. From there you could check the first character in each token to see if it's a number, an operator, or a variable and just do the operations. Using RPN instead of normal notation would also help.
Also, accessing "a" from the global environment requires using _env
, typed using puny font. That's a feature from normal Lua that Pico-8 still has unchanged but doesn't document, which is why it needs puny font to be entered correctly. _env
is a table containing to all global variables declared as part of your program.
Agh, it gets more complex from there though, @kimiyoribaka. Thus the desire to have the parser for numbers (and variables) automated.
It was something I tried to tackle years ago but then also ran into the problem that division takes precedence over multiplication takes precedence over subtraction takes precedence over addition. And if you had something like this: 6+8*3/4
it would really be:
6+8*3/4 6+8*(3/4) 6+8*.75 6+(8*.75) 6+6 12 |
And it can get much more complex than that if you have added custom parentheses in the formula. Is why I'd rather there be an internal parser for this sort of thing.
Can you please post an example of code using _ENV ?
Sure. Here's what I used right before posted to verify that I was remembering it correctly:
a=17 seq="a" print(_ENV[seq]) |
Trying out the your code, @kimiyoribaka.
Those of you where it's crashing, make sure to press CTRL+P when you type "_env" and then press CTRL+P when you are done. It should appear in small caps.
OK that is interesting. Here is another way to show it.
apple=17 seq="ap" seq=seq.."ple" print(_𝘦𝘯𝘷[seq]) |
With _env[] this proves that you can enter in a real string and it will instead return that variable name. This opens up some interesting ideas in building a programming language within a programming language.
It does not work with arrays, however:
apple={} apple[1]=17 seq="ap" seq=seq.."ple[1]" print(_𝘦𝘯𝘷[seq]) |
The result for that is [NIL]
However it can be tricked this way:
apple={} apple[1]=17 fruit=apple[1] seq="fr" seq=seq.."uit" print(_𝘦𝘯𝘷[seq]) |
Resulting in the correct 17
Yet now all we need is something for print(env["1+2*fruit"])
to internally calculate and we're all set.
Self-modifying code like you can do in Bagel would get this too:
sum="print(1+2*3/4)" env(sum) |
I didn't feel like doing my actual work at the moment, so I made a solution for that. I thought about going one step further making a solution that dereferences brackets too, but then I got stuck on how to elegantly deal with all the special cases that come up in the ways of doing things I came up with. Also it requires recursion to do any solution that doesn't choose a specific number of layers of abstraction.
Anyway, here's an example of how you can evaluate that string:
function eval(s) local adds = split(s,"+",false) local prev_aval = 0 for a in all(adds) do local mults = split(a,"*",false) local prev_mval for m in all(mults) do local mval=tonum(m) if (not mval) mval=_𝘦𝘯𝘷[m] prev_mval=(prev_mval and (prev_mval * mval) or mval) end prev_aval+=prev_mval end return prev_aval end fruit = 17 print(eval("1+2*fruit")) |
Regarding how to parse further things. Parentheses and brackets both would need recursion, which isn't that hard if you're willing to trust the stack to be big enough. The part I didn't feel like dealing with at the moment is needing to match left and right brackets while grabbing bits of the string to hand to the recursive call. The other basic math operators are not hard to deal with, but they are a bit tedious. Basically, the commutative property means that it doesn't matter what order the code evaluates math operators of equal precedence as long as they being handled with correct math. I would not suggest trying to treat equal precedence operators in a truly equal manner, though, as the split function is not convenient enough to elegantly deal with multiple delimiters.
Edit: Oh, also just remembered! The above code doesn't handle spaces correctly, because I don't how to elegantly trim strings in pico-8. The only method that came to mind was to split with " " as the delimiter and search the results for non-empty elements, which just feels wrong.
> It does not work with arrays, however:
to be precise, _ENV[name]
works with everything, in that it will return the value associated to that name. it’s print that doesn’t know how to print tables usefully.
@merwok
That's not the issue. _𝘦𝘯𝘷["apple[1]"]
isn't asking for the value of apple[1]
. It's asking for the value of the impossible variable with the full name "apple[1]", including the brackets as part of the name. That's why the result ends up being [nil]
rather than [table]
. This is a consequence of allowing any string to be a valid key for a table while also storing the global environment as a table that can be accessed.
[Please log in to post a comment]