Wednesday, March 30, 2011

Seq.unfold explanation in f#

Hi, I am trying to create a sequence lazily by using f#.

The sequence is defined as follows:

The nth term of the sequence of triangle numbers is given by, tn = ½n(n+1); so the first ten triangle numbers are:

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

Here is what I have so far but it dosn't seem to work:

let tri_seq = 1.0 |> Seq.unfold (fun x -> match x with                                         
                                          | _ -> Some (x, 0.5*x*(x + 1.0)))

Thankyou very much who can help me figure out how unfold works. Thanks

edit: I marked the first answer as correct but it dosnt work, however i slightly modified it and it worked.

let tri_seq = 1.0 |> Seq.unfold (fun x -> Some (0.5 * x * (x + 1.0),x + 1.0))
From stackoverflow
  • First off, why do you use match if you've got only one case?

    let tri_seq = 1.0 |> Seq.unfold (fun x -> Some (x, 0.5 * x * (x + 1.0)))
    

    Second, what “doesn't seem to work”? Are you aware that you produce an infinite list?

    /Edit: For completeness’ sake, here’s the correct solution, which the OP found himself and posted as a comment:

    let tri_seq = 
        1.0 |> Seq.unfold (fun x -> Some (0.5 * x * (x + 1.0), x + 1.0))
    
    masfenix : I tried that, but the sequence just returns one.. > tri_seq;; val it : seq = seq [1.0; 1.0; 1.0; 1.0; ...]
    masfenix : let tri_seq = 1.0 |> Seq.unfold (fun x -> Some (0.5 * x * (x + 1.0),x + 1.0)) is what i needed. Thankyou very much.
  • Here is an alternative:

    let tri = seq {
        let n = ref 1.0
        let diff = ref 2.0
        while true do
            yield !n
            n := !n + !diff
            diff := !diff + 1.0
        }
    
    printfn "%A" (tri |> Seq.take 10 |> Seq.to_list)
    
  • Another alternative to the code that Brian posted is to use recursion instead of imperative 'while' loop:

    let tri = 
      let rec loop(n, diff) = seq { 
        yield n        
        yield! loop(n + diff, diff + 1.0) }
      loop(1.0, 2.0)
    printfn "%A" (tri |> Seq.take 10 |> Seq.to_list)
    

    It is far less efficient (so you have to be a bit careful here...), but it is more idiomatic functional solution, so it may be easier to see what the code does.

    masfenix : Thankyou, but i have no idea what the "Seq { }" does, not "yield" keyword, and lets not talk about the "!". If you can take some time to explain, it would be appreciated!
    Benjol : Not an expert, but Seq {} means make me a sequence out of this. yield is same as C# - means send back value and wait for calling code to ask for next. yield! is (I believe) like Seq.concat - flattens the seq returned from recursive call and does a yield on each element.

0 comments:

Post a Comment