How do I make a custom ++, -=, += operator in lua? Since it lacks increment/decrementing operators.
I'm trying to and here's my code:
local opTable = {}
debug.setmetatable(0, {
__call = function(a, op)
return opTable[op](a)
end
})
opTable["++", int + 1] -- The rest of the code works, this is the main line that's the problem.
local x = 2;
print(x++)
I also want to know how to do +=, and -=, or maybe how to do /= or *= and %=.
You can't make custom operators in Lua. It is not possible.
Your __call metamethod (if it actually works) would allow you to call x("++") (i.e. it allows you to call a number), not x++, and it would return x+1 without modifying x.
opTable["++", int + 1] makes no sense as a Lua statement. You probably wanted something like this:
opTable["++"] = function(int)
return int + 1
end
but it still won't do what you want. The syntax will still be x("++") and it will return x+1 and it won't modify x.
Related
i'm trying to develop the algorithm W in f# for type inference, but i would like to understand how to write the function for generating fresh variables properly.
Actually my function is
let counter = ref -1
let generate_fresh_variable () : string =
let list_variables = ['a' .. 'z'] |> List.map string
counter.Value <- !counter + 1
list_variables.Item(!counter)
but i'm not satisfy with this solution, someone can give me other better ideas?
If you really want to do this with an impure function, I would write it like this:
let mutable counter = -1
let generate_fresh_variable () =
counter <- counter + 1
counter + int 'a'
|> char
|> string
Notes:
Reference cells are obsolete. If you need impurity, use mutable variables instead. (Alternatively, if you really want to stick with a reference cell, the canonical way to update it is with :=, rather than assigning directly to the underlying Value.)
There's no need to maintain a list of potential variable names (and there's especially no need to rebuild the entire list each time you generate a fresh variable).
What happens if you need more than 26 variables?
If you wanted to use some more sophisticated F# tricks, you could create an inifinte sequence of names using a sequence expression (which makes it very easy to handle the looping and dealing with >26 names):
let names = seq {
for i in Seq.initInfinite id do
for c in 'a' .. 'z' do
if i = 0 then yield string c
else yield string c + string i }
A function to get the fresh name would then pick the next name from the sequence. You need to do this using the underlying enumerator. Another nice trick is to hide the state in a local variable and return a function using lambda:
let freshName =
let en = names.GetEnumerator()
fun () ->
ignore(en.MoveNext())
en.Current
Then just call freshName() as many times as you need.
I want to use a variable that references an arithmetic operator within an if statement expression as shown below:
str = { '>60', '>60', '>-60', '=0' }
del = 75
function decode_prog(var1, var2)
op = string.sub(var1, 1, 1)
vb = tonumber(string.sub(var1, 2, 3))
if var2 op vb then
print("condition met")
else
print('condition not meet')
end
end
for i = 1, #str do
decode_prog(str[i], del)
end
When the above code executes, it should either print "condition met" or "condition not met" based on the result of the operation, however I am instead receiving an error.
You cannot substitute a native Lua operator with a variable that references a function, the only way to go about what you are attempted to do is to create a set of functions within an associative array and set the index as a reference to the respective operation you want to conduct.
Looking at your list, you have a greater than (>) and equal to (=). We create a table for these operations that takes two parameters as follows.
local operators = {
[">"] = function(x, y) return x > y end,
["="] = function(x, y) return x == y end,
-- Add more operations as required.
}
You can then invoke the respective function from the decode_prog function by obtaining the operation character from the string, along with the numeric value itself - this is possible because you can obtain the function from the associative array where the index is the string of the operation we want to conduct.
local result = operators[op](var2, number)
This calls upon the operators array, uses the op to determine which index we need to go to for our appropriate operation, and returns the value.
Final Code:
str = { '>60', '>60', '>-60', '=0' }
del = 75
local operators = {
[">"] = function(x, y) return x > y end,
["="] = function(x, y) return x == y end,
}
function decode_prog(var1, var2)
local op = string.sub(var1, 1, 1) -- Fetch the arithmetic operator we intend to use.
local number = tonumber(string.sub(var1, 2)) -- Strip the operator from the number string and convert the result to a numeric value.
local result = operators[op](var2, number) -- Invoke the respective function from the operators table based on what character we see at position one.
if result then
print("condition met")
else
print('condition not meet')
end
end
for i = 1, #str do
decode_prog(str[i], del)
end
I can't make much sense of your code or what you want to achieve doing that but if could simply use load.
You build your expression as a string and run it. Of course you should take care of two character operators like >= which I did not and you should validate your input.
local str={'>60','>60','>-60','=0'}
local del=75
function decode_prog(var1, var2)
local operator = var1:sub(1,1):gsub("=", "==")
local expr = string.format("return %d %s %s", var2,operator, var1:sub(2))
print(string.format("condition %smet", load(expr)() and "" or "not "))
end
for i,v in ipairs(str) do
decode_prog(v, del)
end
A very simple way would be to add a condition for each supported operator:
function decode_prog(var1, var2)
op = string.sub(var1, 1, 1)
vb = tonumber(string.sub(var1, 2)) --remove the last argument and use tonumber()
if vb == nil then return end --if the string does not contain number
if (op == ">" and var2 > vb) or (op == "=" and var2 == vb) --[[add more conditions here]] then
print("condition met")
else
print("condition not met")
end
end
I changed the vb=string.sub(var1,2,3) line too.
This form vb = tonumber(string.sub(var1, 2)) will allow use of numbers that have any number of digits and added tonumber() which will allow us to catch not-a-number errors when comparison would probably fail.
Then I added a logic to determine what the operator is and if the condition is met.
Operator limitations:
This will only work with operators that are one character and operator such as >= will not be possible unless you use a different character for it. ≥ will not play nicely, since it is multiple characters.
The following code got compilation error:
var a : Int = 0
var b : Int = 3
var sum : Int = 0
while (sum = a+b) < 2 {
}
The error message is:
Cannot invoke '<' with an argument list of type '((()),
IntegerLiteralConvertible)'
How to solve this problem? (Of course I can put sum assignment statement out side the while statement. But this is not convenient. Any other advice? Thanks
In many other languages, including C and Objective-C, sum = a+b would return the value of sum, so it could be compared.
In Swift, this doesn't work. This was done intentionally to avoid a common programmer error. From The Swift Programming Language:
Swift supports most standard C operators and improves several capabilities to eliminate common coding errors. The assignment operator (=) does not return a value, to prevent it from being mistakenly used when the equal to operator (==) is intended.
Since the assignment operator does not return a value, it can't be compared with another value.
It is not possible to overload the default assignment operator (=), but you could create a new operator or overload one of the compound operators to add this functionality. However, this would be unintuitive to future readers of your code, so you may want to simply move the assignment to a separate line.
In most languages, assignments propagate their value -- that is, when you call
sum = a + b
the new value of sum is available for another part of the expression:
doubleSum = (sum = a + b) * 2
Swift doesn't work that way -- the value of sum isn't available after the assignment, so it can't be compared in your while statement. From Apple's documentation:
This feature prevents the assignment operator (=) from being used by
accident when the equal to operator (==) is actually intended. By
making if x = y invalid, Swift helps you to avoid these kinds of
errors in your code.
The other answers explain why your code won't compile. Here is how you can clean it up without calculating sum in the while loop (I'm assuming you want to be able to reassign what sum's getter is, elsewhere.):
var a = 0, b = 3
var getSum = { a + b }
var sum: Int { return getSum() }
while sum < 2 {
...and if you're okay with invoking sum with parentheses:
var a = 0, b = 3
var sum = { a + b }
while sum() < 2 {
You can rewrite it as a for loop, although you'll have to repeat the assignment and addition:
for sum = a+b; sum < 2; sum = a+b {
}
I'm wokring with Lua 5.2, and for the sake of this question, assume that the tables are used exclusively as arrays.
Here's a function that returns the tail of an array (the array minus its first element):
function tail(t)
if # t <= 1 then
return nil
end
local newtable = {}
for i, v in ipairs(t) do
if i > 1 then
table.insert(newtable, v)
end
end
return newtable
end
For instance:
prompt> table.concat(tail({10, 23, 8}), ", ")
23, 8
However this is achieved by returning a new copy of the table. Is there a way to avoid the creation of a new table?
I am looking for the equivalent of C's returning a pointer to the next element (t++). Is it possible?
As already explained, this is normally impossible.
However, using metatables, you could implement a tail function that performs what you want without copying all the data, by referencing the original table. The following works for most operations in Lua 5.2, but for example not for table.concat:
function tail(t)
return setmetatable({}, {
__index = function(_, k) return t[k+1] end,
__newindex = function(_, k, v) t[k+1] = v end,
__len = function(_) return #t-1 end,
__ipairs = function(_) return
function(_, i)
if i+1==#t then return nil end
return i+1, t[i+2] end,
t, 0 end,
__pairs = function(t) return ipairs(t) end,
})
end
This is the nicest way I know to implement tail(). It makes one new table, but I don't think that's avoidable.
function tail(list)
return { select(2, unpack(list)) }
end
Nicol is correct that you can't reference a slice of an array, but there is an easier/shorter way to do what you want to do:
function tail(t)
local function helper(head, ...) return #{...} > 0 and {...} or nil end
return helper((table.unpack or unpack)(t))
end
print(table.concat(tail({10, 23, 8}), ", ")) will then print 23,8.
(added table.unpack or unpack to make it also work with Lua 5.2)
I am looking for the equivalent of C's returning a pointer to the next element (t++). Is it possible?
No. The only possible reason you could want this is performance. Such a feature is only found in low-level programming languages. Lua is a scripting language: performance is not such a priority that this would be implemented.
Just make another table like you're doing, or use table.remove to modify the original. Whichever works best for you. Remember: the big, important objects like tables and userdata are all stored by reference in Lua, not by value.
prapin's suggestion, to use metatables to present a view of the sequence, is roughly the way I'd do it. An abstraction that might help is defining a metatable for segments, which can be an 0-ary function that returns a pair of a table and an offset index - we are only using functions here to represent tuples. We can then define a metatable that makes this function behave like a table:
do
local tail_mt = {
__index = function(f, k) local t, i=f(); return t[k+i] end,
__newindex = function(f, k, v) local t,i=f(); t[k+1] = v end,
__len = function(f) local t,i=f(); return #t-i end,
__ipairs = function(f)
local t,i = f ()
return
function (_, j)
if i+j>=#t then
return nil
else
return j+1, t[i+j+1]
end
end, nil, 0
end,
}
tail_mt.__pairs = tail_mt.__ipairs -- prapin collapsed this functionality, so I do too
function tail (t)
if type(t) == "table" then
return setmetatable ( function () return t, 1 end, tail_mt )
elseif type(t) == "function" then
local t1, i = t ()
return setmetatable ( function () return t1, i+1 end, tail_mt )
end
end
end
With __index and __newindex metamethods, you can write code such as f[2]=f[1]+1.
Although this (untested) code doesn't endlessly create one-off metatables, it is probably less efficient than prapin's, since it will be calling thunks (0-ary functions) to get at their contents. But if you might be interested in extending the functionality, say by having more general views on the sequence, I think this is a bit more flexible.
In C I can do following:
#define S1(x) #x
#define S(x) S1(x)
#define foo(x) bar(x, S(x))
int obj = 3;
foo(obj);
void bar(int v, const char * name)
{
// v == 3
// name == "obj"
}
Can I do the same in Lua?
foo(barbar)
function foo(ob)
-- can I get "barbar"?
end
I think you could do something similar only by using a preprocessor which does something similar to your C preprocessor code. (The plain C compiler can't do something like that, too.)
Or write it explicitly:
foo(barbar, "barbar")
You Could do this, but as DeadMG suggested: don't.
A way would be:
function foo(bar)
return bar
end
print(foo(bar)) -- prints nil
setmetatable(_G,{__index=function(t,k)
if k:match"^_" then -- Don't use on system variables
return nil
else
return k
end
end})
print(foo(bar)) -- prints bar
But I would strongly comment against it, as this can have nasty side effects.
No, I don't believe you can. The use of such is dubious to begin with.