Question

Étant donné ce qui suit:

#light
//any function returning bool * 'a
let foo =
    let x = ref 10
    fun () ->
        x := !x - 1
        if !x <> 0 then
            (true, x)
        else
            (false, x)

while let (c,x) = foo() in c do print_any x;//can't access x, but would be convinent.

//this is how I want it to work, without all the typing
let rec loop f =
    match f() with
    | (true, x) ->
        print_any x
        loop f
    | (false, _) -> ()
loop foo

Comment dois-je résoudre ce problème? Ou devrais-je simplement passer par les tracas de convertir "foo" à une expression de séquence?

Était-ce utile?

La solution

C’est une solution, mais je pense personnellement que c’est un abus de la construction en temps réel.

#light
while 
   (let (c,x) = foo()
    if c then print_any !x
    c)
   do ()

Autres conseils

Une autre solution qui est légèrement meilleure à mon avis. Il extrait x de la portée de la clause condition de la commande while et la place dans une référence y disponible dans la portée supérieure. Ce n’est toujours pas la meilleure solution (fonctionnelle), mais ça marche.

let y = ref 1
while (let (c,x) = foo()
       y := !x
       c)
       do printf "%i" !y

Je pense que votre solution rec loop fonctionne mieux car elle est la plus fonctionnelle (évite les effets secondaires bien que foo utilise l'état) et la plus générale (elle fonctionne sur toutes les fonctions du même temps. comme foo). La saisie est plus longue, mais si vous utilisez plus de fonctions comme foo, la boucle est plus productive que la solution la plus courte, juste pour foo.

Je voudrais même généraliser une boucle de plus et faire abstraction de l'action que vous voulez faire avec une valeur dans une situation "vraie":

let loop f a = 
   let rec loop2() = 
      match f() with
      | (true, x) ->
         a x
         loop2()
      | (false, _) -> ()
   loop2()

loop foo print_any

J'aime les autres suggestions sur la façon de consommer " foo " en supposant que foo soit maintenu fixe.

À mon avis, le code de " foo " sent. S'il est raisonnable de convertir " foo " pour " bar " dans le sens de

let bar =    
    let x = ref 10    
    seq {
        x := !x - 1        
        while !x <> 0 do
            yield x
            x := !x - 1        
    }
bar |> Seq.iter print_any

alors je le ferais, mais "bar", même si un peu mieux, semble encore louche. (Dans "bar", j'ai conservé l'aspect inhabituel qui renvoie "int ref" plutôt que simplement "int", comme "foo" l'a fait, mais j'espère que cet aspect n'était pas intentionnel?)

Je pense que la chose la plus géniale à propos de "foo" C’est le genre d’information implicite qui n’est pas évidente dans le type de données (vous pouvez continuer à l’appeler tant que la partie bool est vraie), ce qui rend la version seq un peu plus attrayante.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top