2009-11-30 11 views
8

Pouvez-vous passer dans une opération comme « diviser par 2 » ou « soustraire 1 » en utilisant seulement un opérateur partiellement appliquée, où « ajouter 1 » ressemble à ceci:F # passer un opérateur avec des arguments à une fonction

List.map ((+) 1) [1..5];; //equals [2..6] 
// instead of having to write: List.map (fun x-> x+1) [1..5] 

Ce qui se passe est que 1 est appliqué à (+) comme premier argument, et que l'élément de liste est appliqué comme deuxième argument. Pour l'addition et la multiplication, cet ordre d'argument n'a pas d'importance.

Supposons que je veux soustraire 1 de chaque élément (ce sera probablement une erreur de débutants commun):

List.map ((-) 1) [1..5];; //equals [0 .. -4], the opposite of what we wanted 

1 est appliqué sur la (-) comme premier argument, donc au lieu de (list_item - 1), je obtenez (1 - list_item). Je peux réécrire comme l'ajout d'un négatif au lieu de soustraction positif:

List.map ((+) -1) [1..5];; 
List.map (fun x -> x-1) [1..5];; // this works too 

Je suis à la recherche d'une façon plus expressive de l'écrire, quelque chose comme ((-) _ 1), où _ désigne un espace réservé, comme dans la langue Arc. Cela provoquerait 1 être le second argument à -, donc dans List.map, il évaluerait à list_item - 1. Donc, si vous vouliez carte divide by 2 à la liste, vous pouvez écrire:

List.map ((/) _ 2) [2;4;6] //not real syntax, but would equal [1;2;3] 
List.map (fun x -> x/2) [2;4;6] //real syntax equivalent of the above 

cela peut être fait ou dois-je utiliser (fun x -> x/2)? Il semble que le plus proche de la syntaxe de l'espace réservé est d'utiliser un lambda avec un argument nommé.

Répondre

11

Vous pouvez écrire une fonction flip, quelque chose comme:

let flip f x y = f y x 

List.map (flip (-) 1) [2;4;6] 

je peux avoir la syntaxe mal, je ne suis pas terriblement parle couramment F #.

+8

Votre flip-function peut (tout aussi bien) être définie comme 'laisser flip f x y = f y x' –

+0

C'est un bon candidat pour l'inline. –

8

Il n'y a pas de 'sections d'opération' dans F #, à la Haskell, ni d'arguments d'espace réservé (apparemment à l'Arc). Vous pouvez utiliser un combinateur «flip» comme suggéré dans une autre réponse pour inverser l'ordre des arguments et ensuite appliquer partiellement le premier (maintenant second) argument.

Mais je voudrais simplement utiliser

fun x -> x/2 

À moins que vous jouez le code-golf, je ne pense pas que d'essayer de se raser encore quelques personnages hors ici vous quoi que ce soit achète.

8

Le flip -solution suggéré par Logan Capaldo peut également être écrit en utilisant un opérateur (ici >.):

let (>.) x f = (fun y -> f y x) 
List.map (1 >. (-)) [2;4;6] 

Ou si vous préférez opérandes l'inverse:

let (>.) f x = (fun y -> f y x) 
List.map ((-) >. 1) [2;4;6] 

Modifier : L'utilisation d'un opérateur qui "ressemble plus à un espace réservé" (ici >-<) vous rapproche de votre syntaxe suggérée:

List.map ((-) >-< 1) [2;4;6] 

'_' est malheureusement (?) Pas a valid operator symbol in F#.

+1

:) Smiley. :(frownie.: p tongue.> - .un oeil a piqué dehors. (frownie avec un oeil a piqué dehors. – Juliet

Questions connexes