Karim Belabas on Fri, 15 Feb 2013 18:32:57 +0100 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
Re: PARI 2.6 syntax 1: iferr/iferrname |
* Bill Allombert [2013-02-14 22:42]: [...] > This is an example of the iferr interface: > > invmod(a,N)= > { > iferr(Mod(b,N)^-1 > ,E, my(T); > if(errname(E)=="e_INV"&&type(T=component(E,2))=="t_INTMOD", > return([gcd(lift(T),N)]) > ,error(E))); > } > > iferrname allows to simplify a bit: > > invmod(a,N)= > { > iferrname("e_INV" > ,Mod(b,N)^-1 > ,E ,my(T); > if(type(T=component(E,2))=="t_INTMOD", > return([gcd(lift(T),N)]) > ,error(E))); > } > > but the imbricated 'if' seems clumsy. > Maybe we could allow: > > my(T); > iferrname("e_INV", Mod(b,N)^-1 > ,E > ,type(T=component(E,2))=="t_INTMOD" > ,return([gcd(lift(T),N)])) > > Better idea ? I am not sure that two separate functions iferr / iferrname are useful. We could have a single iferr() -- corresponding to current iferrname -- with the following syntax: iferr("error_name" /* (1) */ , /* code that may raise an exception (2) */ , /* variable E containing the error, optionnally some_predicate(E) (3) */ , /* recovery code (4) */ ) (1) "error_name" is optional. Omitting it results in current iferr() behaviour: trap all runtime exceptions. Otherwise only trap exceptions with the expected name. (2) is straightforward (3) must contain a variable name, say E, to store the exception context for later manipulations. I like the idea of being able to ascertain that the exception is the one we intended to catch for complicated cases (unlike your toy example above where the "not invertible" exception can only come from a t_INTMOD, making the test spurious) But it's not that nice to impose an extra argument in the frequent case where the code is simple enough to *know* that an exception with the expected name can only come from the "right" error. I see two possibilities: * sol. 1: "binding" the predicate to the error E: allow either - a variable name, says 'E' by itself (current syntax) - or something like E | some_predicate(E) [ to be read "E such that..." ] Probably impossible without introducing yet another argument code. You tell us :-) * sol. 2: having two functions, the simple iferr(), with just a variable name, and a more complicated iferrtest(), say, with an extra argument corresponding to a predicate E must satisfy in order for us to catch this particular exception. This seems very easy to implement, without introducing a new argument code. (4) is relatively straightforward. Non-obvious part: it can use component(E,i) [ or Vec(E) ] to access the exception context and recover in a sensible way. Such as returning an integer factor in your toy example. Independently of the above, it would be "nice" to support a simplified form in the case where the exception context 'E' is not needed at all (no predicate on E, and E unused in the recovery code): iferr("error_name" /* (1) */ , /* code that may raise an exception (2) */ , /* recovery code (4) */ ) (only 3 arguments). I am not sure whether this is a good idea [ have the argument semantic depend on the total number of arguments received by the function ], and it only saves 2 or 3 keystrokes :-) > iferrname("e_DOMAIN", > exp(-tan(x)^2) > ,E > ,if(component(E,1)=="tan" && component(E,4)=="Pi/2 + kPi" > ,0 > ,error(E))) sol. 1: iferr("e_DOMAIN", exp(-tan(x)^2) , E | my([f,v,op,lim,x] = Vec(E)); f=="tan" && lim=="Pi/2 + kPi" , 0); sol. 2: iferrtest("e_DOMAIN", exp(-tan(x)^2) , E, my([f,v,op,lim,x] = Vec(E)); f=="tan" && lim=="Pi/2 + kPi" , 0); 1) see ??e_DOMAIN@ for an explanation of the [f,v,op,lim,x] notations :-) 2) no need to rethrow E at the end since if some_predicate(E) does not evaluate to "true" (non-zero), we don't catch E at all. Cheers, K.B. -- Karim Belabas, IMB (UMR 5251) Tel: (+33) (0)5 40 00 26 17 Universite Bordeaux 1 Fax: (+33) (0)5 40 00 69 50 351, cours de la Liberation http://www.math.u-bordeaux1.fr/~belabas/ F-33405 Talence (France) http://pari.math.u-bordeaux1.fr/ [PARI/GP] `