Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refactoring F# while-do "mutable" code into functional "immutable" code

I have been trying to re-write one of my simple C# console app into purely functional F# code (if at all possible). Up until now I have managed to re-write while blocks into "immutable" F# with the help of Seq (something like Seq.initInfinite sequenceGenerator |> Seq.takeWhile condition |> Seq.iter bodyOfWhileCycle) - the website "F# for Fun and Profit" has been my inspiration.
However, this time I came across a simple while block that in "mutable" F# looks like follows (and it works):

printfn "Type low OP number"
let mutable lowLimit = parseMe (Console.ReadLine())                    
printfn "Type high OP number"
let mutable highLimit = parseMe (Console.ReadLine())                                            
let mutable myCondition = true
if highLimit > lowLimit then myCondition <- false            
while myCondition do 
      printfn "Type low OP number again"
      lowLimit <- parseMe (Console.ReadLine())                                  
      printfn "Type high OP number again"
      highLimit <- parseMe (Console.ReadLine())
      if highLimit > lowLimit then myCondition <- false

Can anyone help me to figure out how to refactor this "mutable" while-do block into a functional style? My attempts to refactor it do not work the way I want - I do not know how to get the lowLimit1/highLimit1 values out of the bodyOfWhileCycle function. One of my unsuccessfull attempts is here:

printfn "Type low OP number"
let lowLimit = parseMe (Console.ReadLine())                       
printfn "Type high OP number"
let highLimit = parseMe (Console.ReadLine())
let verifyingInputValues: unit = 
    let bodyOfWhileCycle _=    
                            printfn "Type low OP number again"
                            let lowLimit1 = parseMe (Console.ReadLine())                                  
                            printfn "Type high OP number again"
                            let highLimit1 = parseMe (Console.ReadLine())
                            ()                
    fun _ -> highLimit - lowLimit 
    |>  Seq.initInfinite 
    |>  Seq.takeWhile ((>) 0)
    |>  Seq.iter bodyOfWhileCycle   
verifyingInputValues
like image 891
Miroslav Husťák Avatar asked May 11 '26 03:05

Miroslav Husťák


1 Answers

It looks like you want to have the while loop finish when highLimit > lowLimit and otherwise repeat requests, and presumably, do something with them later.

In which case you want a function that returns a tuple of ( highLimit, lowLimit ) and not unit (). A recursive function can handle the apparent change in state or IO between calls, without mutability, by passing the new state in as an argument.

let fullParse: () -> int *int =
    let parseHighLow again = 
       printfn "Type low OP number %s" again
       let lowLimit = parseMe (Console.ReadLine())                                  
       printfn "Type high OP number %s" again
       let highLimit = parseMe (Console.ReadLine())
       highLimit, lowLimit
        
    let rec verify (high, low) = 
       if high > low  then high, low else verify (parseHighLow "again")
    verify (parseHighLow "")

let (high, low) = fullParse ()
like image 146
Martin Freedman Avatar answered May 12 '26 18:05

Martin Freedman