How to Create an Infix %Between% Operator

How can I create an infix %between% operator?

You can define infix operators as functions:

`%between%`<-function(x,rng) x>rng[1] & x<rng[2]
1 %between% c(0,3)
# [1] TRUE
1 %between% c(2,3)
# [1] FALSE

As pointed out by @flodel, this operator is vectorized:

1:5 %between% c(1.5,3.5)
# [1] FALSE TRUE TRUE FALSE FALSE

How can you create an infix operator that applies to every class and struct?

If all you want is an operator that applies a closure to whatever type you throw at it, than a protocol isn't really the right approach here. A plain generic operator (function) will do the trick:

infix operator =>

@discardableResult func => <T>(this: T, _ delegate: (T) -> ()) -> T {
delegate(this)
return this
}

This can be used in exactly the way you outline, without needing to extend anything.

Defining an infix operator for use within a formula

You do not need to define a new operator in this case: in a formula d1/d2 expands to d1 + d1:d2. In other words d1/d2 specifies that d2 is nested within d1. Continuing your example:

out3 <- lm(y ~ cut(v2,breaks=c(0,.25,.8,1))/I(v1 < .3))
all.equal(coef(out1), coef(out3))
# [1] TRUE

Further comments

Factors may be crossed or nested. Two factors are crossed if it possible to observe every combination of levels of the two factors, e.g. sex and treatment, temperature and pH, etc. A factor is nested within another if each level of that factor can only be observed within one of the levels of the other factor, e.g. town and country, staff member and store etc.

These relationships are reflected in the parametrization of the model. For crossed factors we use d1*d2 or d1 + d2 + d1:d2, to give the main effect of each factor, plus the interaction. For nested factors we use d1/d2 or d1 + d1:d2 to give a separate submodel of the form 1 + d2 for each level of d1.

The idea of nesting is not restricted to factors, for example we may use sex/x to fit a separate linear regression on x for males and females.

In a formula, %in% is equivalent to :, but it may be used to emphasize the nested, or hierarchical structure of the data/model. For example, a + b %in% a is the same as a + a:b, but reading it as "a plus b within a" gives a better description of the model being fitted. Even so, using / has the advantage of simplifying the model formula at the same time as emphasizing the structure.

R: conflict between two definitions of (infix) operator: how to specify package?

Adding from @MrFlick's comment:

Unfortunately you can't use namespaces with infix operators in R; the parser just won't recognize that syntax. You need to create an alias as suggested in the answer below. Or create your own version of the operator that does dispatching based on the classes you expect to see.


Just an idea but: how about redefining the infix function's binding. Suppose the one from ggplot2 is the one you are going to use most often in your code:

library(ggplot2)
`%+c%` <- crayon::`%+%`

This way you are correctly namespacing the ggplot2 library and you just use a different binding for the crayon one.

How to convert any method to infix operator in ruby

A bit late to the party but I've been toying around with it and you can use operator overloading to create Infix operators just like in python (but with a bit more work), the syntax becomes a |op| b, here's how:

First a quick and dirty copy-paste to play around with Infix:

class Infix def initialize*a,&b;raise'arguments size mismatch'if a.length<0||a.length>3;raise'both method and b passed'if a.length!=0&&b;raise'no arguments passed'if a.length==0&&!b;@m=a.length>0? a[0].class==Symbol ? method(a[0]):a[0]:b;if a.length==3;@c=a[1];@s=a[2]end end;def|o;if@c;o.class==Infix ? self:@m.(@s,o)else;raise'missing first operand'end end;def coerce o;[Infix.new(@m,true,o),self]end;def v o;Infix.new(@m,true,o)end end;[NilClass,FalseClass,TrueClass,Object,Array].each{|c|c.prepend Module.new{def|o;o.class==Infix ? o.v(self):super end}};def Infix*a,&b;Infix.new *a,&b end
#

Ok

Step 1: create the Infix class

class Infix
def initialize *args, &block
raise 'error: arguments size mismatch' if args.length < 0 or args.length > 3
raise 'error: both method and block passed' if args.length != 0 and block
raise 'error: no arguments passed' if args.length == 0 and not block
@method = args.length > 0 ? args[0].class == Symbol ? method(args[0]) : args[0] : block
if args.length == 3; @coerced = args[1]; @stored_operand = args[2] end
end
def | other
if @coerced
other.class == Infix ? self : @method.call(@stored_operand, other)
else
raise 'error: missing first operand'
end
end
def coerce other
[Infix.new(@method, true, other), self]
end
def convert other
Infix.new(@method, true, other)
end
end

Step 2: fix all the classes that don't have a | method and the three special cases (true, false, and nil) (note: you can add any class in here and it will probably work fine)

[ NilClass, FalseClass, TrueClass,
Float, Symbol, String, Rational,
Complex, Hash, Array, Range, Regexp
].each {|c| c.prepend Module.new {
def | other
other.class == Infix ? other.convert(self) : super
end}}

Step 3: define your operators in one of 5 ways

# Lambda
pow = Infix.new -> (x, y) {x ** y}
# Block
mod = Infix.new {|x, y| x % y}
# Proc
avg = Infix.new Proc.new {|x, y| (x + y) / 2.0}
# Defining a method on the spot (the method stays)
pick = Infix.new def pick_method x, y
[x, y][rand 2]
end
# Based on an existing method
def diff_method x, y
(x - y).abs
end
diff = Infix.new :diff_method

Step 4: use them (spacing doesn't matter):

2 |pow| 3      # => 8
9|mod|4 # => 1
3| avg |6 # => 4.5
0 | pick | 1 # => 0 or 1 (randomly chosen)

You can even kinda sorta curry:
(This only works with the first operand)

diff_from_3 = 3 |diff

diff_from_3| 2 # => 1
diff_from_3| 4 # => 1
diff_from_3| -3 # => 6

As a bonus, this little method allows you to define Infixes (or any object really) without using .new:

def Infix *args, &block
Infix.new *args, &block
end

pow = Infix -> (x, y) {x ** y} # and so on

All that's left to do is wrap it up in a module

Hope this helped

P.S. You can muck about with the operators to have something like a <<op>> b, a -op- b, a >op> b and a <op<b for directionality, a **op** b for precedence and any other combination you want but beware when using true, false and nil as the first operand with logical operators (|, &&, not, etc.) as they tend to return before the infix operator is called.

For example: false |equivalent_of_or| 5 # => true if you don't correct.

FINALLY, run this to check a bunch of cases of all the builtin classes as both the first and second operand:

# pp prints both inputs
pp = Infix -> (x, y) {"x: #{x}\ny: #{y}\n\n"}

[ true, false, nil, 0, 3, -5, 1.5, -3.7, :e, :'3%4s', 'to',
/no/, /(?: [^A-g7-9]\s)(\w{2,3})*?/,
Rational(3), Rational(-9.5), Complex(1), Complex(0.2, -4.6),
{}, {e: 4, :u => 'h', 12 => [2, 3]},
[], [5, 't', :o, 2.2, -Rational(3)], (1..2), (7...9)
].each {|i| puts i.class; puts i |pp| i}

R: How to best import infix operators like %% into my package?

I'm not sure if there's a single best practice in this case.
Using @importFrom to update the NAMESPACE file is indeed to be a package-wide directive,
but I've never come across a package that had problems with that,
or reasons to avoid it.
You can annotate several functions with the same @importFrom directive if you like,
denoting which functions use which imports,
and it won't cause any conflicts;
it's entirely up to you though,
a single one would suffice.
Using @import might be frowned upon,
but I think it really depends on which package you import.

From your question I gather you use :: explicitly
(which I would personally say is good practice),
and then you don't even need to alter the NAMESPACE.
For most cases that would be just fine,
though there can be very special cases that usually need to be considered individually.
These special cases, at least in my experience, are usually related with S4 generics.

Take for instance the base::rowSums function:
it is not a generic function in base,
but if the Matrix package is attached,
rowSums is "transformed" into an S4 generic,
but the generic is not in the base package.
Why that's the case is beyond the scope of this answer
(see ?Methods_for_Nongenerics for more information),
but it means that if your package uses the notation base::rowSums,
it would not dispatch to methods from Matrix.
The only way to support both cases
(i.e. when Matrix is not used by the user and when it is)
would be to use rowSums without base::.

Now, regarding infix operators,
if you wanted to use ::,
you'd need something like base::`%in%`("a", c("a", "b")),
which essentially entails using it as a function and losing the infix syntax,
something you probably don't want.

So unless you have very specific reasons to avoid one or the other,
just use whatever notation you prefer.
I'd personally stick to :: as much as possible,
but would never use it for infix operators.

R calling infix function with more than 2 parameters

To call an infix function with more than 2 arguments you will need to use its prefix form:

`%sum%` <- function(x, y, z = 0) x + y + z

4 %sum% 5
## [1] 9

`%sum%`(4, 5, 6)
## [1] 15

Alternately redefine it so that it only requires 2 arguments.

Creating infix operators in Scala

You can define implicit class

implicit class Iff(val b: Boolean) extends AnyVal {
def <=>(that: Boolean) = this.b == that
}

and now you can call it without using new :

true <=> false // false
false <=> true // false
true <=> true // true


Related Topics



Leave a reply



Submit