2011-01-13 1 views
4

J'ai besoin d'une fonction qui retourne (non imprime) de manière récursive toutes les valeurs d'une liste à chaque itération. Cependant, chaque fois que j'essaye de programmer cela, ma fonction retourne une liste à la place.Fonction récursive qui retourne toutes les valeurs dans la liste (In OCaml)

let rec elements list = match list with 
| [] -> [] 
| h::t -> h; elements t;; 

J'ai besoin d'utiliser chaque élément à chaque fois qu'il est renvoyé dans une autre fonction que je l'ai écrit, donc je besoin de ces éléments un à la fois, mais je ne peux pas comprendre cette partie dehors. Toute aide serait appréciée.

Répondre

3

Votre fonction est équivalente à:

let rec elements list = 
    match list with 
    | [] -> [] 
    | h :: t -> elements t 

Cela se produit parce que a ; b évalue a (et les rejets le résultat) et évalue ensuite et retourne b. Évidemment, cela équivaut à son tour à:

let elements (list : 'a list) = [] 

Cette fonction n'est pas très utile.

Avant d'essayer de résoudre ce problème, cependant, veuillez comprendre que Les fonctions Objective Caml ne peuvent renvoyer qu'une valeur. Renvoyer plus d'une valeur est impossible.

Il existe des moyens de contourner cette limitation. Une solution consiste à emballer toutes les valeurs que vous souhaitez retourner dans une seule valeur: un tuple ou une liste, généralement. Donc, si vous avez besoin de retourner un nombre arbitraire d'éléments, vous les emballer ensemble dans une liste et ont le processus de code d'appel qui liste:

let my_function() = [ 1 ; 2; 3; 4 ] in (* Return four values *) 
List.iter print_int (my_function()) (* Print four values *) 

Une autre solution moins fréquente consiste à fournir une fonction et l'appeler sur chaque résultat:

let my_function action = 
    action 1 ; 
    action 2 ; 
    action 3 ; 
    action 4 
in 
my_function print_int 

Ceci est moins souple, mais sans doute plus rapide, que de retourner une liste: les listes peuvent être filtrées, triées, stockées ...

+0

Merci pour la réponse. J'ai pensé à faire cela en deux étapes avec deux fonctions, comme vous l'avez décrit, mais mon problème est de récupérer chaque élément un par un. Je devrais être un peu plus précis. Ma fonction principale est une fonction de sous-ensemble dans laquelle je dois déterminer si la liste a est un sous-ensemble de la liste b. Je suis obligé d'écrire cette fonction d'une manière qui est polymorphe, mais en ce moment je peux seulement comprendre comment le faire avec une liste d'ints. – Atticus

+0

Le problème est que j'ai écrit une fonction pour retourner le premier élément de la liste: let head list = correspond à la liste avec h :: t -> h | [] -> 0. Comme je dois rendre compte de la liste vide, je renvoie 0, et OCaml détermine que cette fonction prend une liste d'ints. Puisque la fonction de sous-ensemble doit être polymorphe, je ne peux pas savoir à l'avance ce qu'il faut retourner pour l'ensemble vide, que ce soit 0, "null", ou peu importe. Cela me limite donc aux listes d'ints. – Atticus

+0

dans ce cas (que retourner pour la liste vide), il suffit d'élever une erreur: (failwith "erreur") – gasche

1

Votre question est une sorte de confusion - vous voulez une fonction cela retourne toutes les valeurs dans une liste. Eh bien, la façon la plus simple de renvoyer un nombre variable de valeurs est d'utiliser une liste! Essayez-vous peut-être d'émuler les générateurs Python? OCaml n'a rien de similaire à yield, mais remplit généralement la même chose en "passant" une fonction à la valeur (en utilisant iter, fold ou map).

Ce que vous avez actuellement écrit est équivalent dans Python:

def elements(list): 
    if(len(list) == 0): 
     return [] 
    else: 
     list[0] 
     return elements(list[1:]) 

Si vous essayez de le faire:

def elements(list): 
    if(len(list) > 0): 
     yield list[0] 
     # this part is pretty silly but elements returns a generator 
     for e in elements(list[1:]): 
      yield e 

for x in elements([1,2,3,4,5]): 
    dosomething(x) 

L'équivalent en OCaml serait comme ceci:

List.iter dosomething [1;2;3;4;5] 

Si vous essayez de déterminer si la liste a est un sous-ensemble de la liste b (comme je l'ai appris de votre comments), alors on peut tirer parti de List.mem et List.for_all:

List.for_all (fun x -> List.mem x b) a 

fun x -> List.mem x b définit une fonction qui renvoie vrai si la valeur x est égale à un élément quelconque en (est un membre d ') b. List.for_all prend une fonction qui retourne un booléen (dans notre cas, la fonction d'appartenance que nous venons de définir) et une liste. Il applique cette fonction à chaque élément de la liste. Si cette fonction renvoie true pour chaque valeur de la liste, for_all renvoie true. Donc, ce que nous avons fait est: pour tous les éléments de a, vérifiez s'ils sont membres de b. Si vous êtes intéressé par la façon d'écrire vous-même ces fonctions, je vous suggère de lire la source de list.ml, qui (en supposant * nix) se trouve probablement dans/usr/local/lib/ocaml ou/usr/lib/ocaml.

Questions connexes