Is this a toy reduction of a concept that you want to apply in a much more complex way?
On Thu, Jul 2, 2015 at 11:09 AM, Jan Drugowitsch <[email protected]> wrote: > On Thursday, 2 July 2015 16:55:33 UTC+2, Yichao Yu wrote: >> >> On Thu, Jul 2, 2015 at 10:48 AM, Tom Breloff <[email protected]> wrote: >> > Just curious... is there a reason simply checking for non-zero isn't >> enough? >> > Readability? Performance? >> > >> > f(a,b,c) = (Bool(a) ? a * (b + c) : 0.0) >> >> I'm guessing he want all code that gets his type automatically gets >> this behavior? If yes, I don't think there's anyway you can do that. >> If not, then just writing the branch or having a macro to rewrite that >> in your own code is probably the best solution. >> > > Indeed, the reason why I don't want to check for zeros and ones explicitly > is that some of these appear in inner loops and would reduce performance. > > I already thought of macros as a possible solution, but I was wondering if > the same could be achieved in a more implicit/elegant way. > > Thanks, > Jan > > >> > On Thursday, July 2, 2015 at 9:47:59 AM UTC-4, Jan Drugowitsch wrote: >> >> >> >> Dear Julia users, >> >> >> >> I am implementing an algorithm to solve a specific type of Volterra >> >> integral equation, and that simplifies significantly if some of its >> >> parameters are set to zero or one. The function implementing the >> algorithm >> >> takes quite a few arguments, such that writing specific versions for >> >> different arguments being zero/one would lead to too many different >> >> functions, which I would like to avoid. What I would rather like to do >> is to >> >> write one generic function and let the compiler prune different parts >> of the >> >> function, depending on the argument types. >> >> >> >> A minimal example of what I would like to do is >> >> >> >> immutable Zero <: Number; end >> >> >> >> const _zero = Zero() >> >> >> >> Base.promote_rule{T<:Number}(::Type{Zero}, ::Type{T}) = T >> >> Base.convert{T<:Number}(::Type{T}, ::Zero) = zero(T) >> >> >> >> *(::Zero, ::Zero) = _zero >> >> *(::Zero, ::Bool) = _zero >> >> *(::Bool, ::Zero) = _zero >> >> *(::Zero, ::Number) = _zero >> >> *(::Number, ::Zero) = _zero >> >> >> >> f(a, b, c) = a * (println("summing b + c"); b + c) >> >> >> >> println("Evaluating f(0, 1, 2)") >> >> f(0, 1, 2) >> >> println("Evaluating f(_zero, 1, 2)") >> >> f(_zero, 1, 2) >> >> >> >> (with Zero defined similar to >> >> https://groups.google.com/forum/#!topic/julia-users/0ab30bE8q6c) >> >> Running the above results in >> >> >> >> Evaluating f(0, 1, 2) >> >> summing b + c >> >> Evaluating f(_zero, 1, 2) >> >> summing b + c >> >> >> >> even though the result of the second "summing b + c" is discarded, and >> >> therefore wouldn't need to be evaluated. This is no surprise, as >> *(.,.) is a >> >> standard function that evaluates its operands before applying the >> function. >> >> Is there any way to change this behavior and turn *(.,.) into a >> function >> >> that performs short-circuit evaluation? If not, is there an >> alternative >> >> approach that achieves this without writing tons of specialized >> functions? >> >> >> >> Thanks, >> >> Jan >> >
