[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Determining which functions to call
- From: Florian Berger <fberger@...>
- Date: Wed, 22 Jan 2003 18:01:38 +0200 (EET)
Hi.
Thanks for answers. I'm using Lua 4 so metatables were quite difficult to
understand for Lua newbie like me. I compiled Lua 5 beta and tried
metatables solution and it worked. I just have to figure out what excatly
is happening. Below is my current solution. I don't know if it's any good
but opinions are welcome.
Florian
function New(old, init)
local new = init or {}
for k,v in old do
if not new[k] then
new[k] = v
end
end
return new
end
----------------------------
-- Available functions
aryF={}
aryF[1]="Radius"
aryF[2]="Perimeter"
aryF[3]="Area"
-- Function name is index, contains return value and parameters
aryFD={}
aryFD["Radius"]={"RADIUS", "DIAMETER"}
aryFD["Perimeter"]={"PERIMETER", "RADIUS"}
aryFD["Area"]={"AREA", "RADIUS"}
Circle =
{
DIAMETER=6
}
function Radius(self, d)
return d/2
end
function Perimeter(self, r)
return 2*PI*r
end
function Area(self, r)
return PI*(r*r)
end
-----------------------------
function Find(val)
for i=1, getn(aryF) do
if aryFD[aryF[i]][1]==val then
return aryF[i]
end
end
return nil
end
-- Which function is needed to solve given variable?
function SolveFunction(self, VarName)
local FuncName=Find(VarName)
local Parameter=0
local ParameterValues={}
local str, str2
for i=2, getn(aryFD[FuncName]) do
Parameter=aryFD[FuncName][i]
if self[Parameter]==nil then
ParameterValues[i-1]=SolveVariable(self, Parameter)
else
ParameterValues[i-1]=(self[Parameter]);
end
end
str=format("temp=%s(a", FuncName)
for i=2, getn(aryFD[FuncName]) do
str=str..", "
str2=format("%d", ParameterValues[i-1])
str=str..str2
end
str=str..")"
dostring(str)
return temp
end
-- Do we know the value of given variable?
-- If not solve variable using function
function SolveVariable(self, VarName)
if self[VarName] then
return self[VarName]
else
return SolveFunction(self, VarName)
end
end
-- Solve given variable if possible
function Solve(self, str)
if type(self)=="table" then
if type(str)=="string" then
if self[str]==nil then
print(SolveVariable(self, str))
else
print(self[str]);
end
else
print("Second parameter must be a string")
end
else
print("First parameter must be a table");
end
end
---------------
a=New(Circle)
Solve(a, "RADIUS")
Solve(a, "DIAMETER")
Solve(a, "AREA")
Solve(a, "PERIMETER")
-- Output
-- > 3
-- > 6
-- > 28.27
-- > 18.85
>
> Here is another approach which uses Lua's amazing
> tables-are-functions-are-tables worldview. Here I assume that it is ok to
> memoise the result of function calls (which I think works in the case you
> used as an example.)
>
> The basic idea is that the object has a number of property fields which may
> or may not be present. Each one has an associated function defined in terms
> of other field(s). We assume that no function will return "false"; some
> other marker value could be used but it would be uglier. The marker is
> necessary to avoid endless recursion and to identify whether computations
> have the necessary information to proceed or not.
>
> Then we can define everything in terms of an __index metamethod:
>
> function try_to_compute(table, key)
> local func = getmetatable(table)[key]
> if func then
> table.key = false -- mark goal
> local val = func(table) -- try to get the value
> if val
> then table.key = val -- got it, so record it
> return val -- and return it
> else table.key = nil -- nope, reset for next try
> return nil
> end
> end
> end
>
> Note that we use the metatable also for the functions. To set up an
> object, we need to attach the metatable, and we need to include the
> above function as the __index method. So here we go:
>
> function Searcher(props, funcs)
> funcs.__index = try_to_compute
> return setmetatable(props, funcs)
> end
>
> If I were doing this in real life, I would put the definition of
> try_to_compute in Searcher and use a closure instead of getmetatable.
>
> I haven't tried this, but the basic idea would be (my math is a bit rusty
> and I'm a bit sleep-deprived, so apologies in advance for typos and stupid
> errors.)
>
> do
> local funcs = {}
> -- example of a property with two possible formula
> function funcs.radius(t)
> return (t.diameter and t.diameter / 2)
> or (t.circumference and t.circumference / 2 * math.pi
> end
> function funcs.diameter(t)
> return t.radius and t.radius * 2
> end
> function funcs.circumference(t)
> return t.diameter and t.diameter * math.pi
> end
> function funcs.area(t)
> return t.radius and t.radius * t.radius * math.pi
> end
>
> function Circle(props)
> return Searcher(props, funcs)
> end
> end
>
> a = Circle {radius = 27}
> b = Circle {circumference = 40}
>
>
>
>