Am 02.09.2010 13:58, schrieb Doriano Blengino: > Rolf-Werner Eilert ha scritto: >> Am 02.09.2010 11:36, schrieb Doriano Blengino: >> >>> Rolf-Werner Eilert ha scritto: >>> >>>> This is just a general question about programming, it doesn't refer to >>>> Gambas specifically, but I would implement the results in Gambas. >>>> >>>> For some of my bigger projects I have had to implement IF and ELSE and >>>> similar functions. I tried to manage AND, OR etc. too, but I failed. >>>> Somehow I didn't find a proper way of implementing this logic. So up to >>>> now I have filled this gap by simply putting several IF ELSE IF ELSE and >>>> so on within each other. Of course this is somewhat tricky sometimes :-) >>>> >>>> > I am not really sure about what you want. My first guess was that you > wanted more information on *how* to use ANDs and ORs in a gambas program > (and there are also XORs and NOTs). Now I doubt that you want to write a > compiler able to interpret boolean expressions. I will try to explain a > little below. > >> >>> Generally speaking, compilers (or parsers) don't use arrays to store >>> intermediate results. ANDs and ORs are like any other arithmetic >>> operation - they are evaluated left to right, giving precedence when >>> due. But! Especially when speaking about boolean expressions, you can't >>> assume a specific order of evaluation. >>> >> >> Ok... But what about brackets? When the user of my program wants to make >> sure the expressions ARE evaluated in a special order? How does this fit >> in here? >> > Brackets only force precedence in the classic way: > > 2*3+4 -> left to right, because "+" has lower precedence than "*" > 2+3*4 -> first "3*4", because "*" has higher precedence than "+" > (2+3)*4 -> again left to right, because the brackets. > >> >>> Some compiler can even arrange >>> code in such a manner that some computation is be omitted, when at a >>> certain point of the expression the result is already known. This is >>> called short-circuit, and Gambas does *not* use it. To clarify, if I write: >>> >>> IF A> 3 AND B+5> 2 THEN... >>> >>> some runtime could evaluate "A> 3" and, if it founds it false, >>> completely avoid to compute "b+5" and "B+5> 2". Gambas does never do >>> so. >>> >> >> And I would be glad if I managed my own program to be half as clever as >> Gambas is :-) >> >> >> >>> It evaluates "A> 3", obtaining a true/false value. Then it computes >>> "B+5", compares with 2, and obtains another true/false value. Then it >>> computes the AND between the two boolean values, and so it can decide to >>> execute the THEN part or not. >>> >> >> Yep - and how does it organize this? Doesn't it have to look into the >> whole line prior to seeing that there is a "> 2" following in order to >> decide to compute "B+5" first? And doesn't it have to evaluate "A> 3" >> and "B + 5> 2" prior to computing the AND? So everything has to be put >> apart into certain pieces, then evaluated, computed and so on to get a >> final result. >> >> If there's no array way of doing it - how is it done then? >> >> If I go letter-by-letter through the formula text the user of my program >> is giving me, I might at every moment stumble over new surprises :-) >> > Actually you use a stack, which can also be seen as an array (unlimited > array) with an index pointing in it. > An expression starts with a "value", followed by a number of couples of > "operator-next_value". > You read the first value, which is "result". > Then you read the next couple of "operator-value". If there is nothing > more, you evaluate "result operator value" and finish. If there is > something more, peek further at the next "operator2". If it has lower > precedence than the current operator, you evaluate the current step and > go ahead. Otherwise, you add a position in the stack and store current > result and current operator, set "result" equal to the current value and > operator=operator2, and go on. > This is a quick and very simplified form, which does not explain how to > "pop" the stack, and does not manage unary operators (like NOT, unary > minuses, and so on). I only have to add that if you encounter an opening > bracket, all the contents of the bracket have to be regarded as a value. > If you know the HP hand calculators, which use RPN method, you can see > that that method is nothing else than this. To calculate: > > 2+3*6 > > you press in sequence "2" Enter "3" Enter "6" "x" "+". Each time you > press Enter the stack is pushed. Each time you apply an operator, the > stack is popped. > > This could be another way to implement an expression compiler... > >> >>> All this is important if, when evaluating expressions, some collateral >>> result is expected. If, instead evaluating simple variables, you use >>> properties or function calls and, if these properties or function calls >>> do something behind the scenes (some collateral effect), then the order >>> of evaluation can be important, but you should not rely on it. >>> >> >> As far as I can see, I wouldn't risk collateral results in my programs. >> >> >>> The >>> solution in this case is to use temporary boolean variables to force the >>> evaluation of some piece of code, and have a predictable evaluation >>> order. The line of code above could be written like: >>> >>> btemp1 = A> 3 >>> btemp2 = B+5> 2 >>> IF btemp1 and btemp2 THEN... >>> >> >> This would make up for a nice array, wouldn't it? :-) >> > Yes... but only because we wanted to use an array. And anyway, at last > the array is combined into an expression! > The same would be; > > b1 = ... > b2 = ... > b3 = ... > if b1 or b2 and b3 then... > > I mean: we can not get rid of the final expression, so an array does not > help :-) > >> >>> This version of code assures that A and B are always evaluated, and in >>> that given order. >>> >>> That said, when there is more than one possibility, it's a question of >>> style. I personally don't like long sequences of ANDs and ORs, but >>> sometimes they are expressive: >>> >>> IF age<18 or sex=female or state=married or religion<>catholic THEN >>> you_are_not_a_catholic_priest() >>> >> >> Ok. Let's use my printing forms as an example. This is where my need for >> this kind of logic is most urgent. >> >> If I want to have a certificate printed for the number of language >> courses a student is taking, I have to decide how to use the free space >> for the marks. So if it's only 2 languages, there is more space and I >> can keep the places for the marks more apart than if it's 4 languages. >> >> So the line of code in the printing form could read somewhat like (I >> write pseudo code, that's easier here) >> >> IF Instr "courses" = "Spanish" AND Instr "courses" = "Russian" THEN >> print special 4 languages version >> ELSE IF Instr "courses" = "Spanish" OR Instr "courses" = "Russian" THEN >> print 3 languages version >> ELSE >> print 2 languages version >> >> Of course it is possible to do this without any ANDs and ORs, but it >> would make things easier to read. It is really complicated to read now. >> >> Another case which came about yesterday and reminded me to this whole thing: >> >> For example, if a student has booked a certain main course which is more >> expensive than the ordinary one but then books in for another special >> language course, there will be a discount on the main course. >> >> If I have to indicate on a sheet how much the students pay, I have to >> decide: >> >> IF expensive main course THEN >> IF plus special course THEN >> x Euros for main course >> z Euros for special course >> ELSE >> y Euros for main course only >> END IF >> ELSE >> x Euros for main course >> IF special course booked THEN >> z Euros for special course >> END IF >> END IF >> >> If there were ANDs and ORs it would make life somewhat easier ;-) >> >> Furthermore, there are other places in the program where a logical >> sequence with ANDs and ORs could help, and if I managed to program the >> whole thing in a way to be able to use it everywhere, this would open >> more ways of organisation. >> >> There is a filter function for instance to build lists of students in >> different classes and courses. It is very primitive now, it can only >> look for Instr in a single field, then put the name into the list or >> not. If I could use genuine logic, many things would be easier. >> >> Hope I could make this clearer. Your answer already helped, but if using >> arrays is unusual, which way is better then? >> > Uhm... a few considerations. > > If you must implement boolean logic in your program, but you don't need > to let your users input boolean expressions into your program: > You should express a series of "rules" like: > > 1. Course cost is X > 2. Special cost is Y (zero means no special course) > 3. if X>expensive and Y<>0 then X=X-discount > 4. Total cost is X+Y > > or, > > 1. Course cost is X > 2. Special cost is Y > 3. Discount_applied = X>expensive and Y<>0 > 4. if Discount_applied then X=X-discount > 5. print "Total cost is " X+Y > 6. if Discount_applied then print "(discount)" > > Anyway, there is no single way to organize tests (IFs, AND, NOTs...) - > we could read hundreds of different books on the same argument. But you > was true when about gambas you wrote "look at the whole line". You > should collect all the possible data, and group them in temporary > (better say high level) variables, like "Discount_applied". Examine > every rule one after another. Your rule is "If the main course is > expensive, and there is another course, then there is a discount". Ok. > Now suppose that now, or in the future, a new rule is added: "If the > scholar is rich, then no discount can be applied". In a single piece of > code, where you determine Discount_applied, you modify it: > > ... > 3. Discount_applied = X>expensive and Y<>0 > 4. if Scholar_is_rich then Discount_applied = false > ... > > May be that to determine if a scholar is rich you must examine the > family income, and the number of members in the family... another piece > of code that has a single purpose: determine the value of > Scholar_is_rich. May be that you don't want to collect data about > richness of scholars, if not needed (the scholar takes only one course). > Then you must can do like this: > > ... > 3. Discount_applied = X>expensive and Y<>0 > 4. Scholar_is_rich = false > 4. if Discount_applied then calculate_if_scholar_is_reach() > 5. if Scholar_is_rich then Discount_applied = false > ... > > Another kind of problem is if you want to "interpret" boolean > expressions inputted by users. Textual representation of boolean > expressions is powerful, but can be difficult both to interpret and to > input. A table can be easier: > > cond1 -and- cond2 -and- cond3 -and- cond4 > -or- > cond1 -and- cond2 -and- cond3 -and- cond4 > -or- > cond1 -and- cond2 -and- cond3 -and- cond4 > > The words "-and-" and "-or-" are fixed in the logic of the program; the > size of the table is also fixed. > Empty rows and empty fields are ignored. For every possible result > (record), you start by saying "this record is ok". Then you scan all the > rows, ignoring empty ones. If a row succeeds, the record passes. > Every single row has 4 condition, which must be met all together. If one > fails, the row fails. > Every condition is a test in the form "value1 operator value2"; value1 > is a combobox containing fields of the recors (name, surname, ZIP, > course and so on); operator is a combobox containing "=", "<>". Value2 > is inputted by the user. > > Try to use "Search messages..." in your email client (which is > Thunderbird/Icedove, right? :-)). It does something very similar. > > I think to have been exhaustive... but if not, ask for more. > > Regards, > Doriano >
Thank you very much, Doriano, this will help a lot. Especially the idea with the table was very enlighting. I guess I'll manage to fiddle together something like that. If there are more questions, I'll be back :-) Regards Rolf ------------------------------------------------------------------------------ This SF.net Dev2Dev email is sponsored by: Show off your parallel programming skills. Enter the Intel(R) Threading Challenge 2010. http://p.sf.net/sfu/intel-thread-sfd _______________________________________________ Gambas-user mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/gambas-user
