[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: answer to cert question
- From: Rici Lake <lua@...>
- Date: Fri, 24 Jun 2005 10:52:11 -0500
On 24-Jun-05, at 6:25 AM, Customer Support wrote:
On Wed, 22 Jun 2005 - Rici Lake wrote:
"So, if you could provide me with a sample of your Lua code, I might
have a
bit more confidence in your certification program."
I'm sorry that I can't fulfill this request directly. The Lua code
that is
sufficiently complex so that it would be of interest to you is also a
trade
secret for us. (Since it is used in our business operations.)
Ooh, trade secrets. Good thing I don't have any of those. My code is
scattered about all over the place. :)
Actually, I would have been interested in the solution to any
reasonably standard programming problem.
As a
somewhat lesser substitute, here is a question from one of our practice
exams:
This exercise strikes me more as a "I know how to move the pieces"
puzzle than an illustration of programming. Clearly, line 29 would
create an error since coroutine.status requires a thread as an argument
rather than nil, which is what you're providing. However, it's never
reached because of the endless loop in the thread created by cons(). I
suppose that means that the answer is (d), 'there is no output',
although that's not strictly speaking true: eventually something will
happen to terminate the loop, such as an irate sysadmin killing the
process, and you'll receive some sort of notification of that. I don't
know what that proves.
A more useful question would have been: How do you fix the bug(s) in
the following code? But that would require an explanation of what the
code was supposed to do (hard to answer, I would think) and it's not
the sort of question that leads itself to multiple-choice answers.
Anyway, since you provided me with an estimated US$1.00 of sample
questions, I've returned with my S/0.07 at today's exchange rate:
Given the following code:
1 x = 0
2
3 prod = coroutine.create(
4 function()
5 while true do
6 put(x)
7 x = x + 2
8 end
9 end)
The use of a global variable here is very bad style. Clearly, x is
intended to be private to prod, and there is not reason to pollute the
global namespace with it. Usually one would do this with a factory
function:
-- The argument to Producer is the initial value
function Producer(x)
return coroutine.create(
function()
while true do
put(x)
x = x + 2
end
end)
end
Producer() is not a good name for this function, since it says nothing
about what it does. But what does it do?
First, it's clear that put() must at some point call coroutine.yield()
for this to do anything useful at all; otherwise it is simply an
infinite loop. put() might transform x or it might filter x, or both,
but it must eventually call yield(). In any event, one has to ask what
the point of using a global variable for this function is: either it is
simply coroutine.yield(), in which case it would have been clearer just
to say so, or it is effectively a parameter to the factory. And even if
it were, it seems an unnecessary complication to force put to do
something (yield) which we clearly know how to do.
In the event, we have:
18 function put(x)
19 coroutine.yield(x)
20 end
Which is a classic Lua beginner's error. Why add an extra function
wrapper? This should have been written:
put = coroutine.yield
or, better:
local put = coroutine.yield
Since its primary purpose is presumably that the programmer prefers the
word 'put' to the word 'yield'.
But returning to the theme, let's try this:
-- Returns a coroutine which yields those values from the infinite
sequence
-- [init, init+incr, init+2*incr...] for which filter(x) returns a true
value.
function FilteredStep(filter, init, incr)
return coroutine.create(
function()
-- minor efficiencies assuming this will run a lot
local filter, x = filter, init
local yield = coroutine.yield
while true do
if filter(x) then yield(x) end
x = x + incr
end
end
)
end
One might, of course, prefer the use of coroutine.wrap to return a more
easily callable result, as we discover almost immediately on trying to
use it. We might then want a little wrapper, similar to the one in your
example:
22 function get(p)
23 local status, value = coroutine.resume(p)
24 return value
25 end
But that wrapper has a number of problems. First of all, it simply
tosses away the error if there was one. Second, it also tosses away any
return values other than the first one. So we could try to do better:
local function a(...) return arg end
function get(p)
local results = a(coroutine.resume(p))
if a[1] then
table.remove(a, 1)
return unpack(a)
else
error(a[2], 0)
end
end
However, all we have done there is redefine coroutine.wrap()
inefficiently in pure Lua. So we might as well use it in the first
place.
So, let's give all that a whirl:
-- Returns a wrapped coroutine which yields those values from the
infinite sequence
-- [init, init+incr, init+2*incr...] for which filter(x) returns a true
value.
function FilteredStep(filter, init, incr)
return coroutine.wrap(
function()
-- minor efficiencies assuming this will run a lot
local filter, x = filter, init
local yield = coroutine.yield
while true do
if filter(x) then yield(x) end
x = x + incr
end
end
)
end
function test(k)
local function askuser(x)
io.write(string.format("Do you like the number %g? ", x))
return (string.find(io.read('*l'), '^%s*[yY]'))
end
local evens = FilteredStep(askuser, 2, 2)
local negatives = FilteredStep(askuser, -1, -2.5)
local liked = {}
for i = 1, k do
table.insert(liked, (evens()))
table.insert(liked, (negatives()))
end
table.sort(liked)
print("\nYou say you like: "..table.concat(liked, ', '))
end
Before we run this program, can you predict its behaviour?
What is the significance of k?
What order are we going to be asked?
Do coroutines actually help reveal the logic?
What might you do to make the program more user-friendly?
What elementary error have I committed relating to the
handling of stdin in the standalone interpreter?
OK, here we go
> test(3)
Do you like the number 2? yes
Do you like the number -1? yes
Do you like the number 4? no
Do you like the number 6? yes
Do you like the number -3.5? no
Do you like the number -6? not much
Do you like the number -8.5? maybe
Do you like the number -11? yes, ok then
Do you like the number 8? yes
Do you like the number -13.5? no
Do you like the number -16? yep
You say you like: -16, -11, -1, 2, 6, 8