Search code examples
f#type-inference

Type classe, generic memoization


Something quite odd is happening with y types and I quite dont understand if this is justified or not. I would tend to think not.

This code works fine :

   type DictionarySingleton private () = 
      static let mutable instance = Dictionary<string*obj, obj>()
      static member Instance = instance

   let  memoize  (f:'a -> 'b) = 
      fun (x:'a) ->
         let key = f.ToString(), (x :> obj)
         if (DictionarySingleton.Instance).ContainsKey(key) 
         then let r = (DictionarySingleton.Instance).[key]
              r :?> 'b
         else 
              let res = f x 
              (DictionarySingleton.Instance).[key] <- (res :> obj)
              res

And this ones complains

   type DictionarySingleton private () = 
      static let mutable instance = Dictionary<string*obj, _>()
      static member Instance = instance

   let  memoize  (f:'a -> 'b) = 
      fun (x:'a) ->
         let key = f.ToString(), (x :> obj)
         if (DictionarySingleton.Instance).ContainsKey(key) 
         then let r = (DictionarySingleton.Instance).[key]
              r :?> 'b
         else 
              let res = f x 
              (DictionarySingleton.Instance).[key] <- (res :> obj)
              res

The difference is only the underscore in the dictionary definition. The infered types are the same, but the dynamic cast from r to type 'b exhibits an error.

'this runtime coercition ... runtime type tests are not allowed on some types, etc..'

Am I missing something or is it a rough edge ?


Solution

  • If you compile in two steps, first the Type DictionarySingleton, then the Function memoize it works. Looks like the compiler tries first to figure out the type of the underscore (which may be a generic type) and before deciding it's obj it also tries to infer the type of r. So at that point it is still not unified with obj, that's why it fails if you compile in one shot.