Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

string representation of F# function signature

Tags:

let

jupyter

f#

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?

like image 871
Sean Avatar asked Aug 13 '18 18:08

Sean


People also ask

What is F-string notation?

“F-strings provide a way to embed expressions inside string literals, using a minimal syntax. It should be noted that an f-string is really an expression evaluated at run time, not a constant value. In Python source code, an f-string is a literal string, prefixed with f , which contains expressions inside braces.

How do you use F in strings?

To create an f-string, prefix the string with the letter “ f ”. The string itself can be formatted in much the same way that you would with str. format(). F-strings provide a concise and convenient way to embed python expressions inside string literals for formatting.

Is there an F-string?

A g-string, sometimes spelled as gee-string, is a very narrow piece of cloth, either made of plastic or leather, and serves to cover or hold one's genitals. This undergarment passes in between the buttocks, and is seen to be connected to a band held around the waistline or hips.

What is a string representation?

A String is represented as objects in Java. Accordingly, an object contains values stored in instance variables within the object. An object also contains bodies of code that operate upon the object. These bodies of code are called methods.


2 Answers

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 ())
like image 97
Jwosty Avatar answered Oct 05 '22 09:10

Jwosty


You can analyze types representing F# functions, with the help of the Microsoft.FSharp.Reflection namespace. There is the caveat that generic function arguments default to System.Object, and that other F# types which may form incomplete patterns (e.g. union cases, records) are not included.

open Microsoft.FSharp.Reflection
let funString o =
    let rec loop nested t =
        if FSharpType.IsTuple t then
            FSharpType.GetTupleElements t
            |> Array.map (loop true)
            |> String.concat " * "
        elif FSharpType.IsFunction t then
            let fs = if nested then sprintf "(%s -> %s)" else sprintf "%s -> %s"
            let domain, range = FSharpType.GetFunctionElements t
            fs (loop true domain) (loop false range)
        else
            t.FullName
    loop false (o.GetType())

let foo x = x
funString foo
// val it : string = "System.Object -> System.Object"
like image 42
kaefer Avatar answered Oct 05 '22 09:10

kaefer