8
votes

Currying Un Proc avec des arguments de mots clés à Ruby

dire que j'ai un PROC générique code>, lambda code> ou méthode code> qui prend un deuxième argument facultatif:

pow = -> (base:, exp: 2) { base**exp }


1 commentaires

Pour fixer un argument de position arbitraire, voir Stackoverflow.com/a/34813268/477037


4 Réponses :


2
votes
  • Curry ne fonctionne pas avec les arguments de mots clés. Une fonction au curry obtient un paramètre à la fois, ce qui est conceptuellement incompatible avec "tout ordre va bien" des arguments de mots clés.
  • curry doit connaître l'attitude exacte. Si vous appelez simplement curry sans argument, il ignore les options d'option (en cas de pow = -> (base, exp = 2) {base ** exp} , identique à curry (1) ). Utilisez curry (2) pour forcer les deux paramètres. Une fonction au curry ne peut pas connaître un paramètre facultatif suit et lisez l'avenir pour déterminer s'il doit exécuter ou renvoyer une suite au fur et à mesure.

2 commentaires

D'accord. Considérez que le deuxième argument n'est pas facultatif. Comment (si du tout) puis-je faire du curry à partir du deuxième argument? :-)


Afaik, encore une fois pas possible. Curry vous permettra de fournir les arguments dans le même ordre dans la signature de fonction. Si vous voulez curry x. (A, B) dans xc. (A). (A) , vous devrez écrire votre propre: xc = xc = -> (b, a) {x. (A, b)} .Currier ou xc = -> (b) {-> (a) {x. (A) {x. . Sinon, je ne sais pas comment vous communiqueriez l'ordre de paramètre souhaité à Curry .



6
votes

Je ne pense pas que vous puissiez le faire avec proc.curry , mais il y a toujours la solution Longhand xxx

Vous pouvez également créer une fonction d'usine < / p> xxx


1 commentaires

L'idée d'utiliser une fonction d'usine est définitivement intéressante! :-)



8
votes

Vous pouvez construire votre propre méthode de curry aromatisée à mot-clé qui collecte des arguments de mots clés jusqu'à ce que les paramètres requis soient présents. Quelque chose comme: xxx

L'exemple ci-dessus est limité aux arguments de mots clés uniquement, mais vous pouvez certainement l'étendre pour supporter les arguments de mots clés et les arguments de position.


1 commentaires

Merci beaucoup pour l'exemple de mise en œuvre @stefan! Je pensais aussi dans ces lignes, mais je prévois de la nommer #curry . :-P



0
votes

extension @stefan Réponse ci-dessus selon le dernier commentaire et en ligne avec son extrait:

def curry(method)
  -> (*args, **kargs) {
    required  = method.parameters.select { |type, _| type == :req }
    krequired = method.parameters.select { |type, _| type == :keyreq }
    all_args = (required.length <= args.length)
    all_keys = krequired.all? { |_, name| kargs.has_key?(name) }
    if all_args && all_keys
      final_args = (args + kargs.map {|k,v| {k => v} })
      method.call(*final_args)
    else
      -> (*args_, **kargs_) { curry(method)[*args, *args_, **kargs, **kargs_] }
    end
  }
end

def foo(a1, b1, c1 = 5, a2:, b2:, c2: 50)
  { a1: a1, b1: b1, c1: c1, a2: a2, b2: b2, c2: c2}
end

puts foz = curry(method(:foo)) #=> #<Proc:0x0000000003a255f0@./training.rb:56 (lambda)>
puts bar = foz[6,  a2: 60]     #=> #<Proc:0x0000000003a255f0@./training.rb:56 (lambda)>
puts bar[1, b2: 10]            #=> {:a1=>6, :b1=>1, :c1=>5, :a2=>60, :b2=>10, :c2=>50}
puts baz = bar[1]              #=> #<Proc:0x0000000003a17540@./training.rb:64 (lambda)>
puts baz[10, b2: 30, c2: 40]   #=> {:a1=>6, :b1=>1, :c1=>10, :a2=>60, :b2=>30, :c2=>40}


0 commentaires