F# 函数签名的字符串表示
string representation of F# function signature
当我在 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>
是否可以访问这个?
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"
您可以在此基础上轻松编写一个函数,以在值的类型上使用 typeStr
:
let valTypeString x = typStr (x.GetType ())
借助 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# 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>
是否可以访问这个?
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"
您可以在此基础上轻松编写一个函数,以在值的类型上使用 typeStr
:
let valTypeString x = typStr (x.GetType ())
借助 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"