2013-04-24 19 views
7

Come illustrato nell'esempio rubino di seguito, non è possibile chiamare un lambda con un numero errato di argomenti come Proc creato da un Method perché è rigido sul numero di argomenti:Come convertire il metodo o lambda in non-lambda proc

# method with no args 
def a; end 

instance_eval(&method(:a)) 
# ArgumentError: wrong number of arguments (1 for 0) 

method(:a).to_proc.call(1, 2, 3) 
# ArgumentError: wrong number of arguments (3 for 0) 

method(:a).to_proc.lambda? 
# => true 

Come faccio ad avere un Proc che non è una lambda sia da un Proc che è o da un Method?

+0

Per quanto posso dire, non è possibile convertire un metodo o lambda in un proc non-lambda. Cosa stai cercando di realizzare? –

+0

@WallyAltman La semantica chiamante di un blocco, soprattutto per quanto riguarda il numero di argomenti, ma ci sono molte altre differenze. – michelpm

risposta

2

Non c'è modo di farlo.

Oltre all'argomento che passa, mi chiedo cosa ci si aspetterebbe da un return nel metodo. Può comportarsi solo nel modo lambda ...

Se davvero devi fare questo, dovrai costruire il tuo blocco, ad es.

Proc.new{ a } 

Per un modo più generico, si dovrà controllare il arity del metodo e passare solo i parametri richiesti.

+0

Immagino che sia improbabile a causa di 'return',' next' e 'break', come misura temporanea sono stato in grado di scrivere metodi con splat o di farli restituire un' Proc'. C'è un modo per dimostrare che non può essere fatto? – michelpm

+0

@michelpm: nessuna prova, mi dispiace. –

0

Prova avvolgendolo in un non-lambda Proc, in questo modo:

l = lambda {|a,b| puts "a: #{a}, b: #{b}" } 
p = proc {|a,b| l.call(a,b) } 

l.lambda? 
#=> true 
l.arity 
#=> 2 
l.call("hai") 
#=> ArgumentError: wrong number of arguments (1 for 2) 
l.call("hai", "bai", "weee", "womp", "woo") 
#=> ArgumentError: wrong number of arguments (5 for 2) 

p.lambda? 
#=> false 
p.arity 
#=> 2 
p.call("hai") 
#=> a: hai, b: 
p.call("hai", "bai", "weee", "womp", "woo") 
#=> a: hai, b: bai 
0

Converti Lambda a Proc

Ecco un work-around che avvolge un lambda o di una chiamata method in un Proc e usi splat per gestire qualsiasi numero di argomenti:

def lambda_to_proc(lambda) 
    Proc.new do |*args| 
    diff = lambda.arity - args.size 
    diff = 0 if diff.negative? 
    args = args.concat(Array.new(diff, nil)).take(lambda.arity) 

    lambda.call(*args) 
    end 
end 

Questo funzionerebbe sempre indipendentemente dal numero di argomenti passati; Gli argomenti aggiuntivi verranno eliminati e nil sostituirà gli argomenti mancanti.


Esempio:

# lambda with two args 
some_lambda = -> (a,b) { [a, b] } 

# method with no args 
def some_method; "hello!"; end 

lambda_to_proc(some_lambda).call(5) 
# => [5, nil] 

lambda_to_proc(method(:some_method)).call(1,2,3) 
# => "hello!" 

Nota: Non c'è modo diretto per convertire un lambda o di una chiamata di metodo per un proc. Questa è solo una soluzione e ovviamente più lenta rispetto al vero affare (a causa del fatto che una chiamata viene racchiusa in un'altra).

Problemi correlati