open System open Microsoft.FSharp.Core.OptimizedClosures // for 'T = 'T0 -> 'T1 -> ... -> 'Tn, returns the type of 'Tn let codomain<'T> : 'T -> Type = let fsFunctionTypes = [ typedefof> typedefof> typedefof> typedefof> typedefof> ] |> Seq.map (fun t -> t.GUID) |> Set.ofSeq let (|FSharpFunc|_|) (t : Type) = let isFSharpFunc (t: Type) = t <> null && t.IsGenericType && t.GetGenericTypeDefinition().GUID |> fsFunctionTypes.Contains match isFSharpFunc t, isFSharpFunc t.BaseType with | true, _ -> Some t | _, true -> Some t.BaseType | _ -> None let rec traverse = function | FSharpFunc func -> let funcTypes = func.GetGenericArguments() let returningType = funcTypes.[funcTypes.Length - 1] traverse returningType | other -> other fun f -> f.GetType() |> traverse // examples: codomain 2 codomain <| fun x y z w -> (x + y + Int32.Parse(z) + w).ToString() codomain codomain