Ein bisschen spät zur Party, aber ich habe mit ihm wurden Herumspielen und Sie können eine Überlastung verwenden Operator Infixoperatoren nur erstellen wie in python (aber mit ein bisschen mehr Arbeit), wird die Syntax a |op| b
, hier ist wie:
Zuerst eine schnelle und schmutzige Kopie-Paste um mit Infix zu spielen:
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;[email protected];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
Schritt 1: Erstellen Sie die Infix
Klasse
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
Schritt 2: alle Klassen beheben, die keine |
Verfahren und die drei Sonderfälle haben (true
, false
und nil
) (Anmerkung: Sie können jede Klasse hier hinzufügen und es wird wahrscheinlich gut funktionieren)
[ 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}}
Schritt 3: Ihre Betreiber in einem der 5 Arten definieren
# 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
Schritt 4: verwenden sie (Abstand spielt keine Rolle):
2 |pow| 3 # => 8
9|mod|4 # => 1
3| avg |6 # => 4.5
0 | pick | 1 # => 0 or 1 (randomly chosen)
Sie können sogar ein bisschen sorta Curry: (Dies funktioniert nur mit dem ersten Operanden)
Als Bonus können Sie diese kleine Methode definieren Infixe (oder irgendein Objekt wirklich) ohne Verwendung von .new
:
def Infix *args, &block
Infix.new *args, &block
end
pow = Infix -> (x, y) {x ** y} # and so on
Alles, was es zu tun übrig bleibt, wickeln in einem Modul bis
Hope this half
P. S. Sie können mit den Betreibern Dreck über so etwas wie a <<op>> b
zu haben, a -op- b
, a >op> b
und a <op<b
für Direktionalität, a **op** b
für Vorrang und andere Kombination Sie wollen, aber Vorsicht, wenn true
verwenden, false
und nil
als erster Operand mit logischen Operatoren (|
, &&
, not
, usw.), da sie dazu neigen, zurückzukehren, bevor der Infix-Operator aufgerufen wird.
Zum Beispiel: false |equivalent_of_or| 5 # => true
wenn Sie nicht korrigieren.
ENDLICH, diese laufen eine Reihe von Fällen aller eingebauten Klassen als sowohl der ersten und zweiten Operanden zu überprüfen:
# 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}
ich jeden Rubin Beispiel nicht finden können, aber ich gebe nicht zu schreiben, versucht zu haben, Code auf meiner Seite noch – kamaradclimber
Da dies eine Eigenschaft des _parser_ ist, ist es nicht möglich. – mudasobwa