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.
Implicit and elegant sometimes conflict with each other =) If you have control over the code that uses this, using a macro is the way to go. A function can't possibly do this. You could have a look at https://github.com/one-more-minute/Lazy.jl though. > > 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
