Yes, Microsoft.FSharp.Reflection should be used for this sort of thing.

Two same type information that outght to be the same, which are typeof<T> and the v.GetType() where v is a type of T, does not give me same result. ..

This is not the case in F#. The value returned by GetType is under-defined for F# values generated by object expressions and function closures, as specified in section 6.10.21 of the F# spec "Types with Under-specified Object and Type Identity" ([link:research.microsoft.com] - the spec is a draft matching 1.9.4, so if you spot mistakes or incompletenesses please do send them along)

FWIW this is not really the case in C# 3.0 either, where anonymous record types make it impossible to write typeof<T> for some values, so you can hav "v is of type T" but typeof<T> makes no sense. It is also the case that C# values frequently have static types such as IEnumerable<T> but the v.GetType() returns an implementing type. F# is doing the same thing.

The use of null as a representation for unit and option values is documented in the draft F# specification. We are considering having the productized versions of F# will switch to struct representations for these types, where nullness is not an issue, though no final decisions have been made as this can lead to other tradeoffs.

Thanks for the feedback,

don

By on 7/1/2008 10:20 AM ()

Thanks for the reply.

The background story of this posting is: I was trying to write a pretty printing function for types, which is analogous to any_to_string for values, and got some errors to debug. One of them was the null exception, which occured as soon as I used unit value.

The draft I am using is like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
let rec type_to_string (ty : System.Type) =
  let ty = GetTypeOfReprType(ty)
  let rec intersperse y xs =
  match xs with
  | [] -> []
  | [x] -> [x]
  | (x::xs) -> x :: y :: intersperse y xs

  let intersperseArray x xs = xs |> List.of_array |> intersperse x |> Array.of_list

  let intersperseString (c : char) (s : string) = new string(intersperseArray c (s.ToCharArray()))

  let getTyCon (ty : System.Type) = 
  let tc = ty.FullName.Split([|'`'|]).[0]

  if tc.StartsWith("Microsoft.FSharp.Collections.") ||
     tc.StartsWith("Microsoft.FSharp.Core.")
    then (Array.rev (tc.Split([|'.'|]))).[0]
    else tc

  match ty with
  | ty when ty.GetGenericArguments().Length > 0
      -> let tyCon = getTyCon ty
         let tyArgs = ty.GetGenericArguments()
         let tyArgsWithDelim ds = List.reduce_left (^) (intersperse ds [for ty in tyArgs -> type_to_string ty])

         match tyCon with
         | tc when tc = getTyCon (typeof<int list>) -> (tyArgsWithDelim "ERROR LIST MUST HAVE ONE TY PARAM") ^ " list"
         | tc when tc = getTyCon (typeof<int option>) -> (tyArgsWithDelim "ERROR OPTION MUST HAVE ONE TY PARAM") ^ " option"
         | tc when tc = getTyCon (typeof<int * int>) -> "(" ^ (tyArgsWithDelim " * ") ^ ")"
         | tc -> tc ^ "<" ^ (tyArgsWithDelim ", ") ^ ">"

| ty when ty.ToString() = typeof<unit>.ToString() -> "unit" // F# crazyness !! ().GetType() is a null error !!
| ty when ty.ToString() = (1 : int).GetType().ToString() -> "int"
| ty when ty.ToString() = typeof<int>.ToString() -> "int"
| ty when ty.ToString() = (true : bool).ToString() -> "bool"
| ty when ty.ToString() = typeof<bool>.ToString() -> "bool"
| ty when ty.ToString() = (0.0 : float).ToString() -> "float"
| ty when ty.ToString() = typeof<float>.ToString() -> "float"
| ty when ty.ToString() = (0.0 : double).ToString() -> "double"
| ty when ty.ToString() = typeof<double>.ToString() -> "double"
| ty when ty.ToString() = ('a' : char).ToString() -> "char"
| ty when ty.ToString() = typeof<char>.ToString() -> "char"
| ty when ty.ToString() = ("a" : string).ToString() -> "string"
| ty when ty.ToString() = typeof<string>.ToString() -> "string"
| _ -> any_to_string ty


Some obvious improvement to make is using the FSharp.Reflection library to detect whether a type is a list, option, record, or a function.

If there API functions that does the work like this, or if you have any better suggestions, let me know. I hope this kind of function was in the library too.

By on 7/1/2008 12:58 PM ()

I just found out right after posting this. But I am not sure how general this would work. I wish there had been a handy API for this something analogous to RecordType pattern matching.

> (fun (x:int) -> fun (y:int) -> x+y).GetType().BaseType.ToString();;

val it : string

= "Microsoft.FSharp.Core.OptimizedClosures+FastFunc2`3[System.Int32,System.Int32,System.Int32]"

By on 7/1/2008 8:33 AM ()

Have you looked at:
[link:research.microsoft.com]
and:
[link:research.microsoft.com]

I think it's the API you're looking for.

Cheers,
Rob

By on 7/1/2008 8:40 AM ()

Thanks, that was one of the things I needed.

By on 7/1/2008 10:51 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