I'd like to write an iterator that behaves exactly like ipairs, except which takes a second argument. The second argument would be a table of the indices that ipairs should loop over.
I'm wondering if my current approach is inefficient, and how I could improve it with closures.
I'm also open to other methods of accomplishing the same thing. But I like iterators because they're easy to use and debug.
I'll be making references to and using some of the terminology from Programming in Lua (PiL), especially the chapter on closures (chapter 7 in the link).
So I'd like to have this,
ary = {10,20,30,40}
for i,v in selpairs(ary, {1,3}) do
ary[i] = v+5
print(string.format("ary[%d] is now = %g", i, ary[i]))
end
which would output this:
ary[1] is now = 15
ary[3] is now = 35
My current approach is this : (in order: iterator, factory, then generic for)
iter = function (t, s)
s = s + 1
local i = t.sel[s]
local v = t.ary[i]
if v then
return s, i, v
end
end
function selpairs (ary, sel)
local t = {}
t.ary = ary
t.sel = sel
return iter, t, 0
end
ary = {10,20,30,40}
for _,i,v in selpairs(ary, {1,3}) do
ary[i] = v+5
print(string.format("ary[%d] is now = %g", i, ary[i]))
end
-- same output as before
It works. sel is the array of 'selected' indices. ary is the array you want to perform the loop on. Inside iter, s indexes sel, and i indexes ary.
But there are a few glaring problems.
I must always discard the first returned argument s (_ in the for loop). I never need s, but it has to be returned as the first argument since it is the "control variable".
The "invariant state" is actually two invariant states (ary and sel) packed into a single table. Pil says that this is more expensive, and recommends using closures. (Hence my writing this question).
The rest can of this can be ignored. I'm just providing more context for what I'm wanting to use selpairs for.
I'm mostly concerned with the second problem. I'm writing this for a library I'm making for generating music. Doing simple stuff like ary[i] = v+5 won't really be a problem. But when I do stuff like accessing object properties and checking bounds, then I get concerned that the 'invariant state as a table' approach may be creating unnecessary overhead. Should I be concerned about this?
If anything, I'd like to know how to write this with closures just for the knowledge.
Of course, I've tried using closures, but I'm failing to understand the scope of "locals in enclosing functions" and how it relates to a for loop calling an iterator.
As for the first problem, I imagine I could make the control variable a table of s, i, and v. And at the return in iter, unpack the table in the desired order.
But I'm guessing that this is inefficient too.
Eventually, I'd like to write an iterator which does this, except nested into itself. My main data structure is arrays of arrays, so I'd hope to make something like this:
ary_of_arys = {
{10, 20, 30, 40},
{5, 6, 7, 8},
{0.9, 1, 1.1, 1.2},
}
for aoa,i,v in selpairs_inarrays(ary_of_arys, {1,3}, {2,3,4}) do
ary_of_arys[aoa][i] = v+5
end
And this too, could use the table approach, but it'd be nice to know how to take advantage of closures.
I've actually done something similar: A function that basically does the same thing by taking a function as it's fourth and final argument. It works just fine, but would this be less inefficient than an iterator?
You can hide "control variable" in an upvalue:
local function selpairs(ary, sel)
local s = 0
return
function()
s = s + 1
local i = sel[s]
local v = ary[i]
if v then
return i, v
end
end
end
Usage:
local ary = {10,20,30,40}
for i, v in selpairs(ary, {1,3}) do
ary[i] = v+5
print(string.format("ary[%d] is now = %g", i, ary[i]))
end
Nested usage:
local ary_of_arys = {
{10, 20, 30, 40},
{5, 6, 7, 8},
{0.9, 1, 1.1, 1.2},
}
local outer_indices = {1,3}
local inner_indices = {2,3,4}
for aoa, ary in selpairs(ary_of_arys, outer_indices) do
for i, v in selpairs(ary, inner_indices) do
ary[i] = v+5 -- This is the same as ary_of_arys[aoa][i] = v+5
end
end
Not sure if I understand what you want to achive but why not simply write
local values = {"a", "b", "c", "d"}
for i,key in ipairs {3,4,1} do
print(values[key])
end
and so forth, instead of implementing all that interator stuff? I mean your use case is rather simple. It can be easily extended to more dimensions.
And here's a co-routine based possibility:
function selpairs(t,selected)
return coroutine.wrap(function()
for _,k in ipairs(selected) do
coroutine.yield(k,t[k])
end
end)
end
Related
I'm very new to Julia but I've got a some background in Scheme/Rust/F#.
Today I wanted to make yesterday's AoC nicer without an explicit number of nested loops.
I arrived at this working solution, but I don't like the last if. In the languages mentioned above I would call a function (or use a computation expression) that gives me the first result that is not None. For Julia, I expected something to do that. It does, but unexpectedly in an eager fashion.
So When I tried return something(find(r, n, start + 1, which), find(r, n - 1, start + 1, extended)), that also evaluated the second argument when the first already had a result—and thus crashed.
Is there a macro/lazy version or something that I didn't find? How are you supposed to handle a case like that?
I also thought about (short-circuited) or'ing them together, but I guess Julia's strictness in that matter spoils that.
using DataStructures
function find(r::Array{Int}, n, start = 1, which = nil())::Union{Int,Nothing}
if start <= length(r)
extended = cons(start, which)
with_current = sum(i -> r[i], extended)
if with_current == 2020 && n == 1
return prod(i -> r[i], extended)
else
# Unfortunately no :(
#return something(find(r, n, start + 1, which), find(r, n - 1, start + 1, extended))
re = find(r, n, start + 1, which)
if isnothing(re)
return find(r, n - 1, start + 1, extended)
else
re
end
end
end
end
Let me comment more on it why it is not possible given the discussion in the comments.
In Julia function arguments are evaluated eagerly, so Julia evaluates both find(r, n, start + 1, which) and find(r, n - 1, start + 1, extended) before passing them to something function.
Now, with macros you have (I am not writing in a fully general case for simplicity and I hope I got the hygiene right :)):
julia> macro something(x, y)
quote
local vx = $(esc(x))
isnothing(vx) ? $(esc(y)) : vx
end
end
#something (macro with 1 method)
julia> #something 1 2
1
julia> #something nothing 2
2
julia> #something 1 sqrt(-1)
1
julia> #something nothing sqrt(-1)
ERROR: DomainError with -1.0:
sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).
(in a full-blown version of the macro varargs and Some should be handled to replicate something exactly)
Piqued by Bogumił's answer I wanted to write my first Julia macro. It took some time and numerous attempts to figure out syntax, hygiene and escaping but I'm quite happy now.
I thought it might be worth sharing and provide opportunity for suggestions/improvements.
A lazy #something analog to Base.something
function _something_impl(thing)
:(something($(esc(thing))))
end
function _something_impl(thing, rest...)
quote
local evalued = $(esc(thing))
if isnothing(evalued)
$(_something_impl(rest...))
else
something(evalued)
end
end
end
macro something(things...)
_something_impl(things...)
end
Version without exceptions
As I found exceptions raised from a macro like this not quite suitable, I also made a version that falls back to nothing.
function _something_nothing_impl(thing)
quote
local evaluated = $(esc(thing))
if isa(evaluated, Some)
evaluated.value
else
evaluated
end
end
end
function _something_nothing_impl(thing, rest...)
quote
local evalued = $(esc(thing))
if isnothing(evalued)
$(_something_nothing_impl(rest...))
else
something(evalued)
end
end
end
macro something_nothing(things...)
_something_nothing_impl(things...)
end
Now I guess the recursive middle function could also generated by a macro. :)
I'm trying to convert the following to pointfree style: a function that partially applies a value to the transformer function add before passing in the collection to be iterated over. (Using Ramda.js)
R.compose(
R.map,
R.add
)(1, [1,2,3])
The problem is that R.add is arity 2, as is R.map. I want the application order to be as follows:
add(1)
map(add(1))
map(add(1), [1,2,3])
[add(1,1), add(1,2), add(1,3)]
But what happens instead is this:
add(1, [1,2,3])
map(add(1, [1,2,3]))
<partially applied map, waiting for collection>
Anyone know of a way to specify this behavior?
A plain compose or pipe won't do this because either will absorb all the arguments supplied into the first function. Ramda includes two additional functions that help with this, converge and useWith. In this case useWith is the one that will help:
useWith(map, [add, identity])(1, [1, 2, 3]); //=> [2, 3, 4]
While identity is not absolutely required here, it gives the generated function the correct arity.
Figured it out. If anyone's curious, here's the gist. (You can try it in the console on RamdaJS.com.)
0) For a baseline, here's the pointed version.
func0 = x => R.map(R.add(x))
addOne = func0(1)
addOne([1,2,3]) // [2,3,4]
1) Here's the pointfree core, but it has the ordering problem from the question above.
func1 = R.compose(R.map, R.add)
addOne = func1(1)
addOne([1,2,3]) // [2,3,4])
func1(1, [1,2,3]) // function
2) If the composition is unary (arity 1) 2 invocations are needed apply all params.
func2 = R.unary(R.compose(R.map, R.add))
addOne = func2(1)
addOne([1,2,3]) // [2,3,4])
3) We want one invocation to apply both params, so we uncurry 2.
func3 = R.uncurryN(2, func2)
func3(1, [1,2,3]) // [2,3,4])
4) To prove func2 is composable, let's double the results.
func4 = R.compose(
R.map(R.multiply(2)),
R.uncurryN(2, func2)
)
func4(1, [1,2,3]) // [4,6,8])
5) Substitution gives us a completely pointfree function.
func5 = R.compose(
R.map(R.multiply(2)),
R.uncurryN(2, R.unary(R.compose(
R.map,
R.add
)))
)
func5(1, [1,2,3]) // [4,6,8])
Right now I have an SML function:
method([1,1,1,1,2,2,2,3,3,3]);
returns:
val it = [[2,2,2],[3,3,3]] : int list list
but I need it to return:
val it = [[1,1,1,1],[2,2,2],[3,3,3]] : int list list
This is my current code:
- fun method2(L: int list) =
= if tl(L) = [] then [hd(L)] else
= if hd(tl(L)) = hd(L) then hd(L)::method(tl(L)) else [hd(L)];
- fun method(L: int list) =
= if tl(L) = [] then [] else
= if hd(tl(L)) = hd(L) then method(tl(L)) else
= method2(tl(L))::method(tl(L));
As you can see it misses the first method2 call. Any ideas on how I can fix this? I am completely stumped.
Your problem is here if hd(tl(L)) = hd(L) then method(tl(L)) else. This is saying if the head of the tail is equal to the head, then continue processing, but don't add it to the result list. this will skip the first contiguous chunk of equal values. I would suggest separating the duties of these functions a bit more. The way to do this is to have method2 strip off the next contiguous chunk of values, and return a pair, where the first element will have the contiguous chunk removed, and the second element will have the remaining list. For example, method2([1, 1, 1, 2, 2, 3, 3]) = ([1, 1, 1], [2, 2, 3, 3]) and method2([2, 2, 3, 3]) = ([2, 2], [3, 3]). Now, you can just keep calling method2 until the second part of the pair is nil.
I'm not quite sure what you are trying to do with your code. I would recommend creating a tail recursive helper function which is passed three arguments:
1) The list of lists you are trying to build up
2) The current list you are building up
3) The list you are processing
In your example, a typical call somewhere in the middle of the computation would look like:
helper([[1,1,1,1]], [2,2],[2,3,3,3])
The recursion would work by looking at the head of the last argument ([2,3,3,3]) as well as the head of the list which is currently being built up ([2,2]) and, since they are the same -- the 2 at the end of the last argument is shunted to the list being built up:
helper([[1,1,1,1]], [2,2,2],[3,3,3])
in the next step in the recursion the heads are then compared and found to be different (2 != 3), so the helper function will put the middle list at the front of the list of lists:
helper([[2,2,2], [1,1,1,1]], [3],[3,3])
the middle list is re-initialized to [3] so it will start growing
eventually you reach something like this:
helper([[2,2,2], [1,1,1,1]], [3,3,3],[])
the [3,3,3] is then tacked onto the list of lists and the reverse of this list is returned.
Once such a helper function is defined, the main method checks for an empty list and, if not empty, initializes the first call to the helper function. The following code fleshes out theses ideas -- using pattern-matching style rather than hd and tl (I am not a big fan of using those functions explicitly -- it makes the code too Lisp-like). If this is homework then you should probably thoroughly understand how it works and then translate it to code involving hd and tl since your professor would regard it as plagiarized if you use things you haven't yet studied and haven't made it your own work:
fun helper (xs, ys, []) = rev (ys::xs)
| helper (xs, y::ys, z::zs) =
if y = z
then helper(xs, z :: y :: ys, zs)
else helper((y::ys)::xs,[z],zs);
fun method [] = []
| method (x::xs) = helper([],[x],xs);
An example of what I desire:
local X = {["Alpha"] = 5, ["Beta"] = this.Alpha+3}
print(X.Beta) --> error: [string "stdin"]:1: attempt to index global 'this' (a nil value)
is there a way to get this working, or a substitute I can use without too much code bloat(I want it to look presentable, so fenv hacks are out of the picture)
if anyone wants to take a crack at lua, repl.it is a good testing webpage for quick scripts
No there is no way to do this because the table does not yet exist and there is no notion of "self" in Lua (except via syntactic sugar for table methods). You have to do it in two steps:
local X = {["Alpha"] = 5}
X["Beta"] = X.Alpha+3
Note that you only need the square brackets if your key is not a string or if it is a string with characters other than any of [a-z][A-Z][0-9]_.
local X = {Alpha = 5}
X.Beta = X.Alpha+3
Update:
Based on what I saw on your pastebin, you probably should do this slightly differently:
local Alpha = 5
local X = {
Alpha = Alpha,
Beta = Alpha+3,
Gamma = someFunction(Alpha),
Eta = Alpha:method()
}
(obviously Alpha has no method because in the example it is a number but you get the idea, just wanted to show if Alpha were an object).
So I have a table that holds references to other tables like:
local a = newObject()
a.collection = {}
for i = 1, 100 do
local b = newObject()
a[#a + 1] = b
end
Now if I want to see if a particular object is within "a" I have to use pairs like so:
local z = a.collection[ 99 ]
for i,j in pairs( a.collection ) do
if j == z then
return true
end
end
The z object is in the 99th spot and I would have to wait for pairs to iterate all the way throughout the other 98 objects. This set up is making my program crawl. Is there a way to make some sort of key that isn't a string or a table to table comparison that is a one liner? Like:
if a.collection[{z}] then return true end
Thanks in advance!
Why are you storing the object in the value slot and not the key slot of the table?
local a = newObject()
a.collection = {}
for i = 1, 100 do
local b = newObject()
a.collection[b] = i
end
to see if a particular object is within "a"
return a.collection[b]
If you need integer indexed access to the collection, store it both ways:
local a = newObject()
a.collection = {}
for i = 1, 100 do
local b = newObject()
a.collection[i] = b
a.collection[b] = i
end
Finding:
local z = a.collection[99]
if a.collection[z] then return true end
Don't know if it's faster or not, but maybe this helps:
Filling:
local a = {}
a.collection = {}
for i = 1, 100 do
local b = {}
a.collection[b] = true -- Table / Object as index
end
Finding:
local z = a.collection[99]
if a.collection[z] then return true end
If that's not what you wanted to do you can break your whole array into smaller buckets and use a hash to keep track which object belongs to which bucket.
you might want to consider switching from using pairs() to using a regular for loop and indexing the table, pairs() seems to be slower on larger collections of tables.
for i=1, #a.collection do
if a.collection[i] == z then
return true
end
end
i compared the speed of iterating through a collection of 1 million tables using both pairs() and table indexing, and the indexing was a little bit faster every time. try it yourself using os.clock() to profile your code.
i can't really think of a faster way of your solution other than using some kind of hashing function to set unique indexes into the a.collection table. however, doing this would make getting a specific table out a non-trivial task (you wouldn't just be able to do a.collection[99], you'd have to iterate through until you found one you wanted. but then you could easily test if the table was in a.collection by doing something like a.collection[hashFunc(z)] ~= nil...)