F#函数签名的字符串表示

F#函数签名的字符串表示,f#,jupyter,let,F#,Jupyter,Let,当我在F#REPLfsharpi中工作时,每当我输入一个新函数时,签名会在输入后打印出来: > let foo x = x;; val foo : x:'a -> 'a 有没有办法将其作为字符串检索?我问这个问题的原因是,我在Jupyter笔记本电脑上使用IfSharp,它不显示签名,但我希望能够显示用于演示目的的函数类型 我搞砸了一点,但找不到任何有用的东西,我试过: let foo x = (x, x) printfn "%A" (foo.GetType()) printfn

当我在F#REPL
fsharpi中工作时,每当我输入一个新函数时,签名会在输入后打印出来:

> let foo x = x;;
val foo : x:'a -> 'a
有没有办法将其作为字符串检索?我问这个问题的原因是,我在Jupyter笔记本电脑上使用IfSharp,它不显示签名,但我希望能够显示用于演示目的的函数类型

我搞砸了一点,但找不到任何有用的东西,我试过:

let foo x = (x, x)
printfn "%A" (foo.GetType())
printfn "%A" foo
但这并不是我所需要的:

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

有可能访问它吗?

AFAIK,FSharp.Core中没有函数可以获取编译器所看到的类型的字符串表示形式(尽管可能在FSharp.compiler.Services中有一些东西——我还没有检查)。以下是一个适用于大多数简单用途的小函数:

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"

Microsoft.FSharp.Reflection
命名空间的帮助下,您可以分析表示F#函数的类型。需要注意的是,通用函数参数默认为
System.Object
,其他可能形成不完整模式的F#类型(例如联合案例、记录)不包括在内

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"

不幸的是,我不确定F#lib中是否真的有这样一个函数。然而,为此编写自己的函数可能并不难。
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"