2010-07-10 4 views
5

Je suis nouveau à F # et moi avons récemment découvert l'opérateur de composition de fonction >>F # Composition des fonctions avec entrées multiples paramètres

Je comprends le principe de base de sorte que quelque chose comme cela est possible ....

let Add1ToNum x = x +1 
let Mul2ToNum y = y * 2 
let FuncComp = Add1ToNum >> Mul2ToNum 

Cependant, comment peut-on gérer la composition lorsque vous avez plusieurs fonctions qui ont un nombre variable de paramètres d'entrée ... par exemple, je voudrais pouvoir faire ce qui suit ...

let AddNums (x,y) = x+y 
let MulNums (x,y) = x*y 
let FuncComp = Add1 >> Mul2 

Ce qui ne fonctionne évidemment pas car AddNums retourne un int, et MulNums attend un tuple.

Existe-t-il une forme de syntaxe qui me permet d'y parvenir ou, si je veux utiliser la fonction de composition, dois-je toujours effectuer une sorte de fonction intermédiaire pour transformer les valeurs?

Toute suggestion à ce sujet serait grandement appréciée.

+4

Je ne vois pas tout à fait votre point d'utiliser 'AddNum >> MulNums', la sortie de AddNums est un seul numéro, donc pas le format d'entrée valide de MulNums, ce qui signifie la deux fonctions ne sont tout simplement pas composites. –

Répondre

8

Comme Yin et codekaizen ont souligné, vous ne pouvez pas composer les deux fonctions pour créer une fonction qui passe l'entrée à la première et passe ensuite la sortie de cet appel à la deuxième fonction (c'est-à-dire, en utilisant l'opérateur >>). L'utilisation d'un diagramme, vous ne pouvez pas faire:

 +---------+ +---------+ 
--->| AddNums |--->| MulNums |---> 
    +---------+ +---------+ 

Une option est de changer la fonction et spécifier un des paramètres, de sorte que les fonctions peuvent être composées. L'exemple par codekaizen utilise et pourrait également être écrit comme ceci (si vous avez utilisé taitement au lieu des paramètres uplées):

let AddNums x y = x + y 
let MulNums x y = x * y 
let FuncComp = (AddNums 1) >> (MulNums 2) 

Une autre option pour la composition des fonctions est de créer une fonction qui prend plusieurs entrées, passe deux numéros à la première fonction, puis appelle la deuxième fonction avec le résultat et un autre nombre à partir des entrées d'origine. L'utilisation d'un diagramme:

-----------------\ 
--->+---------+ \+---------+ 
--->| AddNums |--->| MulNums |---> 
    +---------+ +---------+ 

Si vous avez besoin quelque chose comme ça, alors la meilleure option est d'écrire que directement, parce que cela ne sera probablement pas un modèle souvent répété.Directement, cela est facile (en utilisant la variante cari):

let AddNums x y = x + y 
let MulNums x y = x * y 
let FuncComp x y z = AddNums z y |> (MulNums z) 

Si vous voulez écrire quelque chose comme ça plus généralement (ou tout simplement par curiosité), vous pouvez écrire quelque chose comme ça (en utilisant la version uplées des fonctions de cette temps). L'opérateur &&& est inspiré par Arrows:

let AddNums (x,y) = x + y 
let MulNums (x,y) = x * y 

let (&&&) f g (a, b) = (f a, g b) 
let FuncComp = (AddNums &&& id) >> MulNums 

// First two numbers are added, result is multiplied by the third one 
FuncComp ((9, 12), 2) // Gives '42' 
+0

Merci Thomas, cela explique très bien! –

+0

@Tomas: Je crains que vous ayez utilisé le mauvais opérateur de Flèches. Devrait être (***);) – Gustavo

+0

let (***) f g (a, b) = (f a, g b) let (&&&) f g a = (f a, g a) – ben

1

Comme le souligne Yin, vos types ne correspondent pas lors de la composition. AddNums et MulNums sont de type int * int -> int, donc vous ne pouvez pas vous attendre à brancher la sortie de l'un dans l'entrée de l'autre.

Je note que votre dernière ligne est let FuncComp = Add1 >> Mul2 qui pourrait être une faute de frappe, mais donne un aperçu sur la façon dont vous pouvez « lier » les fonctions qui prennent tuples afin qu'ils composent:

let Add1 x = AddNums(x, 1) 
let Mul2 x = MulNums(x, 2) 
let FuncComp = Add1 >> Mul2 

Exécuté:

FuncComp (1) ;;

val il: int = 4

+0

Merci codekaizen, j'ai fait remarquer dans ma question que je savais que la sortie d'une fonction était différente de l'entrée de l'autre fonction et que l'opérateur de composition fonctionnelle ne fonctionnerait pas, mais cherchait une explication possible sur les alternatives. –

1

Une autre option est de faire stack-> fonctions de la pile tout comme une calculatrice RPN. Par exemple:

let bin f = function a :: b :: t -> f b a :: t 
let add = bin (+) 
let mul = bin (*) 

Et peut-être une fonction pour pousser littéraux à la pile:

let lit n t = n :: t 

Ensuite, il est pure composition:

> (lit 9 >> lit 12 >> add >> lit 2 >> mul) [] 
42 

Vous pouvez même ajouter des fonctions brouillant pile:

let drop = function _ :: t -> t 
let dup = function x :: t -> x :: x :: t 
let swap = function x :: y :: t -> y :: x :: t 

Et faire des choses comme:

let square = dup >> mul 
let cube = dup >> dup >> mul >> mul 
let negate = lit -1 >> mul 

Juste une expérience dans la folie!

(Voir aussi http://blogs.msdn.com/b/ashleyf/archive/2011/04/21/programming-is-pointless.aspx)

Questions connexes