Most idiomatic way to write batchesOf size seq in F#

前端 未结 10 557
迷失自我
迷失自我 2020-12-16 18:42

I\'m trying to learn F# by rewriting some C# algorithms I have into idiomatic F#.

One of the first functions I\'m trying to rewrite is a batchesOf where:

         


        
10条回答
  •  孤街浪徒
    2020-12-16 18:52

    Implementing this function using the seq<_> type idiomatically is difficult - the type is inherently mutable, so there is no simple nice functional way. Your version is quite inefficient, because it uses Skip repeatedly on the sequence. A better imperative option would be to use GetEnumerator and just iterate over elements using IEnumerator. You can find various imperative options in this snippet: http://fssnip.net/1o

    If you're learning F#, then it is better to try writing the function using F# list type. This way, you can use idiomatic functional style. Then you can write batchesOf using pattern matching with recursion and accumulator argument like this:

    let batchesOf size input = 
      // Inner function that does the actual work.
      // 'input' is the remaining part of the list, 'num' is the number of elements
      // in a current batch, which is stored in 'batch'. Finally, 'acc' is a list of
      // batches (in a reverse order)
      let rec loop input num batch acc =
        match input with
        | [] -> 
            // We've reached the end - add current batch to the list of all
            // batches if it is not empty and return batch (in the right order)
            if batch <> [] then (List.rev batch)::acc else acc
            |> List.rev
        | x::xs when num = size - 1 ->
            // We've reached the end of the batch - add the last element
            // and add batch to the list of batches.
            loop xs 0 [] ((List.rev (x::batch))::acc)
        | x::xs ->
            // Take one element from the input and add it to the current batch
            loop xs (num + 1) (x::batch) acc
      loop input 0 [] []
    

    As a footnote, the imperative version can be made a bit nicer using computation expression for working with IEnumerator, but that's not standard and it is quite advanced trick (for example, see http://fssnip.net/37).

提交回复
热议问题