Your code snippet is analogous to Haskell instance, not Haskell class. This code snippet says that the surrounding type is an instance of IEnumerable<byte>
which would be analogous to something like instance IEnumerable T Byte
in Haskell (where T
is the type in which you implemented IEnumerable
).
I guess the key insight here is that IEnumerable
must be seen as a multiparam type class, with one parameter denoting the type that is the sequence, and the other parameter denoting the element of the sequence.
In F# the first parameter is implicit - it's not mentioned directly on the interface declaration, but every interface has it - it's the type on which the interface is implemented.
// F#
type MyType = MyType with
interface IEnumerable<byte> with
member this.GetEnumerator() = xyz
-- Haskell
class IEnumerable t e where
getEnumerator :: t -> [e]
data MyType = MyType
instance IEnumerable MyType Byte where
getEnumerator t = xyz
Here, it's easy to see that both t
and e
would in fact be "rigid" types. The multiparam-ness reflects the fact that the same type t
may have multiple IEnumerable
implementations for different e
, same way you can implement multiple concrete IEnumerable<e>
on a type in F#.
The one thing that F# cannot do (as such) is provide an implementation for any e
, like this:
instance IEnumerable MyType e where
getEnumerator t = ...
To achieve a similar (though not identical) effect in F#, one would create another interface and implement it:
type AnyEnumerable =
abstract member AnyEnumerate<'a>() : IEnumerable<'a>
type MyType = MyType with
interface AnyEnumerable with
member this.AnyEnumerate<'a>() =
{ new IEnumerable<'a> with
member this.GetEnumerator() = ... }
let x = MyType.AnyEnumerate<int>()
let y = MyType.AnyEnumerate<string>()