Hi,
the best solution I can think of is to use interfaces. This works quite well for collections, because all collection types implement a non-generic interface IEnumerable. This means that your function length doesn't have to be polymorphic and can take the collection as a parameter of type IEnumerable.

F# then gives you function Seq.cast that converts this "untyped" type to a typed version that can be used with Seq.xyz functions. This may not be safe if you convert the collection to anything else than sequence of objects (obj type that corresponds to System.Object), but for calculating the length, this will work just fine.

1
2
3
4
5
6
7
8
9
 
let f2 (length:IEnumerable -> int) x y =
  length x + length y

let length x = x |> Seq.cast |> Seq.length
let r2 =  f2 length [1;2] ["j"]

// Or you can write just...
let r2 =  f2 (Seq.cast >> Seq.length) [1;2] ["j"]

You can of course use the same trick when implementing your own types - a functionality that can be invoked regardless of the actual type instantiation can be exposed in some non-generic interface.

T.

By on 2/12/2009 3:35 AM ()

Hello Tomas,

Thank you for your replies to my specific example.

But the goal of my code snippet was to illustrate a more general feature of the F# type system. I could have used any other function instead then List.length.

Inded in the call to the f2 function, there is absolutely no reason why the code could not be executed. Only the type system refuses to type it.

let f2 length x y =
length x + length y

let r2 = f2 List.length [1;2] ["j"]

In fact,in the call to f2, F# should able to type the argument 'length' in the expression 'length x' as (int list -> int) and to (string list ->int) in the expression 'length y'.
In fact that is what happens in f3, with some help of the developer.

F# does not work that way. I do not know whether it is theoritically feasible in a language such as F#. I guess it is not, that is why haskell has introduced type classes (I only suspect)

But maybe there is a general solution to this, within F# in its current state... I do not know... asking.

Thanks

Regards

J-C

By on 2/12/2009 5:33 AM ()

There's no way within F# to use a parameter of type of (forall 'a. 'a list -> int) and apply it to two lists with different types, so the example you're using can't be done exactly as you might want it to be. You can create a type with a member of type (forall 'a. 'a list -> int), though, and apply that generic member to lists of different types, so you can encode a solution to your problem as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type applyList<'b> = 

  abstract app : 'a list -> 'b 

let f2 (x:applyList<_>) a b = x.app a + x.app b 

type length() = 

  interface applyList<int><INT> with 

    member x.app x = List.length x 

f2 (length()) [1;2] ['j'] 
By on 2/12/2009 7:49 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper