2017-06-14 2 views
17

De Operators.id<'T> Function (F#):Quel est le but de la fonction `id` dans FSharp.Core?

La fonction d'identité.

Paramètres: x Type: « T (valeur d'entrée)

Valeur de retour: La même valeur

F # Core Library Versions, prises en charge dans: 2.0, 4.0, Portable

Pourquoi Y at-il une fonction qui retourne son entrée?

+3

Intéressant de noter le fond mathématique aussi bien. Avoir un objet «ne rien faire» donne une structure importante.Comme zéro est une identité pour les nombres sous addition, et l'un est une identité pour les nombres sous multiplication, donc 'id' est une identité pour l'ensemble des fonctions sous la composition. Et dans les langages fonctionnels, vous voudrez souvent manipuler des fonctions en tant qu'objets, effectuer des opérations sur eux, etc. –

+0

@matt_t_gregg Si vous postez cela en guise de réponse, je suis sûr que vous obtiendrez quelques upvotes. –

+0

@FyodorSoikin J'étais assez contente que votre réponse couvre les aspects pratiques de la nécessité et de l'utilisation - la chose mathématique que je pensais être plus intéressante. –

Répondre

24

Lorsque vous travaillez avec des fonctions d'ordre supérieur (c.-à-fonctions qui renvoient d'autres fonctions et/ou prendre d'autres fonctions en tant que paramètres), vous devez toujours fournir quelque chose comme paramètre, mais il n'y a pas toujours une réelle la transformation des données que vous souhaitez appliquer.

Par exemple, la fonction Seq.collect aplatit une séquence de séquences et prend une fonction qui renvoie la séquence "imbriquée" pour chaque élément de la séquence "externe". Par exemple, voici comment vous pouvez obtenir la liste de tous les petits-enfants d'un contrôle de l'interface utilisateur d'une sorte:

let control = ... 
let allGrandChildren = control.Children |> Seq.collect (fun c -> c.Children) 

Mais beaucoup de fois, chaque élément de la séquence sera déjà une séquence par lui-même - par exemple , vous pouvez avoir une liste de listes:

let l = [ [1;2]; [3;4]; [5;6] ] 

Dans ce cas, la fonction des paramètres que vous passez à Seq.collect a besoin de retourner simplement l'argument:

let flattened = [ [1;2]; [3;4]; [5;6] ] |> Seq.collect (fun x -> x) 

cette expres sion fun x -> x est une fonction qui retourne juste son argument, également connu sous le nom "fonction d'identité".

let flattened = [ [1;2]; [3;4]; [5;6] ] |> Seq.collect id 

Ses cultures d'utilisation si souvent lorsque vous travaillez avec des fonctions d'ordre supérieur (comme ci-dessus) Seq.collect qu'il mérite une place dans la bibliothèque standard.

Un autre exemple convaincant est Seq.choose - une fonction qui filtre une séquence de valeurs Option et les déballe en même temps. Par exemple, voici comment vous pouvez analyser toutes les chaînes sous forme de nombres et jeter ceux qui ne peuvent pas être analysées:

let tryParse s = match System.Int32.TryParse s with | true, x -> Some x | _ -> None 
let strings = [ "1"; "2"; "foo"; "42" ] 
let numbers = strings |> Seq.choose tryParse // numbers = [1;2;42] 

Mais si vous êtes déjà donné une liste de valeurs Option pour commencer? La fonction d'identité à la rescousse!

let toNumbers optionNumbers = 
    optionNumbers |> Seq.choose id 
+0

L'exemple 'Seq.choose id' est un bon exemple, mais' Seq.collect id' est juste une façon moins lisible de dire 'Seq.concat'. (Cela dit, je suis sûr que j'ai écrit 'Seq.collect id' un certain nombre de fois aussi et cela illustre bien ce que' id' fait bien!) –

11

Il est utile pour certaines fonctions d'ordre supérieur (fonctions prenant des fonctions comme arguments) afin que vous puissiez passer id comme argument au lieu d'écrire le lambda (fun x -> x).

[[1;2]; [3]] |> List.collect id // [1; 2; 3] 
+0

Dans ce cas, vous pourriez juste utiliser 'List.concat' et ce serait plus lisible :-). –