Search code examples
f#jupyterlet

string representation of F# function signature


When I'm working in the F# REPL fsharpi whenever I enter a new function the signature is printed after I've entered them:

> let foo x = x;;
val foo : x:'a -> 'a

Is there a way to retrieve this as a string? The reason I'm asking is that I'm using IfSharp for Jupyter notebooks which doesn't display the signatures, but I'd like to be able to show the types of functions for demonstration purposes.

I've messed around a bit but can't get anything useful, I've tried:

let foo x = (x, x)
printfn "%A" (foo.GetType())
printfn "%A" foo

But this isn't quite what I need:

FSI_0013+clo@3-1
<fun:it@5-2>

Is it possible to access this at all?


Solution

  • AFAIK, there's no function in FSharp.Core for getting a type's string representation as it would appear to the compiler (though maybe there's something in FSharp.Compiler.Services -- I haven't checked). Here's a small function that works for most simple uses:

    open System
    
    let (|TFunc|_|) (typ: Type) =
        if typ.IsGenericType && typ.GetGenericTypeDefinition () = typeof<int->int>.GetGenericTypeDefinition () then
            match typ.GetGenericArguments() with
            | [|targ1; targ2|] -> Some (targ1, targ2)
            | _ -> None
        else
            None
    
    let rec typeStr (typ: Type) =
        match typ with
        | TFunc (TFunc(_, _) as tfunc, t) -> sprintf "(%s) -> %s" (typeStr tfunc) (typeStr t)
        | TFunc (t1, t2) -> sprintf "%s -> %s" (typeStr t1) (typeStr t2)
        | typ when typ = typeof<int> -> "int"
        | typ when typ = typeof<string> -> "string"
        | typ when typ.IsGenericParameter -> sprintf "'%s" (string typ)
        | typ -> string typ
    
    
    typeStr typeof<(string -> (string -> int) -> int) -> int>
    // val it: string = "string -> (string -> int) -> int"
    typeStr (typeof<int->int>.GetGenericTypeDefinition())
    // val it: string = "'T -> 'TResult"
    

    You can easily write a function on top of this to use typeStr on a value's type:

    let valTypeString x = typStr (x.GetType ())