Alexander Battisti
Alexander Battisti

Reputation: 2178

Abstracting over Collection Types

Is there a possibility of writing functions which are generic in respect to collection types they support other than using the seq module?

The goal is, not having to resort to copy and paste when adding new collection functions.

Upvotes: 0

Views: 166

Answers (2)

Joh
Joh

Reputation: 2380

Generic programming with collections can be handled the same way generic programming is done in general: Using generics.

let f (map_fun : ('T1 -> 'T2) -> 'T1s -> 'T2s) (iter_fun : ('T2 -> unit) -> 'T2s -> unit) (ts : 'T1s) (g : 'T1 -> 'T2) (h : 'T2 -> unit)=
    ts
    |> map_fun g
    |> iter_fun h

type A =
    static member F(ts, g, h) = f (Array.map) (Array.iter) ts g h
    static member F(ts, g, h) = f (List.map) (List.iter) ts g h

A bit ugly and verbose, but it's possible. I'm using a class and static members to take advantage of overloading. In your code, you can just use A.F and the correct specialization will be called.

For a prettier solution, see https://stackoverflow.com/questions/979084/what-features-would-you-add-remove-or-change-in-f/987569#987569 Although this feature is enabled only for the core library, it should not be a problem to modify the compiler to allow it in your code. That's possible because the source code of the compiler is open.

Upvotes: 2

Tomas Petricek
Tomas Petricek

Reputation: 243051

The seq<'T> type is the primary way of writing computations that work for any collections in F#. There are a few ways you can work with the type:

  • You can use functions from the Seq module (such as Seq.filter, Seq.windowed etc.)
  • You can use sequence comprehensions (e.g. seq { for x in col -> x * 2 })
  • You can use the underlying (imperative) IEnumerator<'T> type, which is sometimes needed e.g. if you want to implement your own zipping of collections (this is returned by calling GetEnumerator)

This is relatively simple type and it can be used only for reading data from collections. As the result, you'll always get a value of type seq<'T> which is essentially a lazy sequence.

F# doesn't have any mechanism for transforming collections (e.g. generic function taking collection C to collection C with new values) or any mechanism for creating collections (which is available in Haskell or Scala).

In most of the practical cases, I don't find that a problem - most of the work can be done using seq<'T> and when you need a specialized collection (e.g. array for performance), you typically need a slightly different implementation anyway.

Upvotes: 1

Related Questions