3

Coming from an OO background, I am having trouble wrapping my head around how to solve simple issues with FP when trying to avoid mutation.

let mutable run = true
let player1List = ["he"; "ho"; "ha"]

let addValue lst value =
    value :: lst

while run do
    let input = Console.ReadLine()
    addValue player1List input |> printfn "%A"
    if player1List.Length > 5 then 
        run <- false
        printfn "all done" // daz never gunna happen

I know it is ok to use mutation in certain cases, but I am trying to train myself to avoid mutation as the default. With that said, can someone please show me an example of the above w/o using mutation in F#?

The final result should be that player1List continues to grow until the length of items are 6, then exit and print 'all done'

2
  • 1
    BTW: Your code does not actually work. You need run <- false and also addValue should mutate the player1List and store the new value (otherwise you just print it and then ignore it). Commented Sep 11, 2014 at 2:12
  • thanks, that was a type, i changed to <- ... the addValue was meant to be like that for an example since my goal was to avoid mutation. Commented Sep 11, 2014 at 2:17

4 Answers 4

7

The easiest way is to use recursion

open System
let rec makelist l = 
    match l |> List.length with
    |6  -> printfn "all done"; l
    | _ -> makelist ((Console.ReadLine())::l)

makelist []

I also removed some the addValue function as it is far more idiomatic to just use :: in typical F# code.

Your original code also has a common problem for new F# coders that you use run = false when you wanted run <- false. In F#, = is always for comparison. The compiler does actually warn about this.

Sign up to request clarification or add additional context in comments.

1 Comment

haha, yea, that = vs <- was just a typo, for my quick proto since I never reached that line, i never saw the fail. Thanks a lot for your answer
4

As others already explained, you can rewrite imperative loops using recursion. This is useful because it is an approach that always works and is quite fundamental to functional programming.

Alternatively, F# provides a rich set of library functions for working with collections, which can actually nicely express the logic that you need. So, you could write something like:

let player1List = ["he"; "ho"; "ha"]
let player2List = Seq.initInfinite (fun _ -> Console.ReadLine())
let listOf6 = Seq.append player1List list2 |> Seq.take 6 |> List.ofSeq 

The idea here is that you create an infinite lazy sequence that reads inputs from the console, append it at the end of your initial player1List and then take first 6 elements.

Depending on what your actual logic is, you might do this a bit differently, but the nice thing is that this is probably closer to the logic that you want to implement...

Comments

2

In F#, we use recursion to do loop. However, if you know how many times you need to iterate, you could use F# List.fold like this to hide the recursion implementation.

[1..6] |> List.fold (fun acc _ -> Console.ReadLine()::acc) []

Comments

1

I would remove the pipe from match for readability but use it in the last expression to avoid extra brackets:

open System

let rec makelist l = 
    match List.length l with
    | 6 -> printfn "all done"; l
    | _ -> Console.ReadLine()::l |> makelist

makelist []

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.