[英]how to get f# signature - visual studio or vs code
I want to be able to explicitly write type signatures in my code. 我希望能够在我的代码中显式地编写类型签名。
VS code will (eventually) generate sort of ghost signatures, but I actually want to explicitly take these generated signatures and type the code. VS代码将(最终)生成某种重影签名,但是我实际上想明确地采用这些生成的签名并键入代码。
Any ideas? 有任何想法吗? I could use FSI, but that can be quite a cumbersome technique. 我可以使用FSI,但这可能是一项繁琐的技术。
Ideally I'd right click and "generate signature"..though that doesn't always fit peoples coding style...I tend to write code; 理想情况下,我会右键单击并“生成签名”。尽管这并不总是适合人们的编码风格,但我倾向于编写代码;
let f : int -> string =
fun i -> i.ToString()
You can get the type of an F# function using the Compiler Services SDK . 您可以使用Compiler Services SDK获得F#函数的类型。 This would require writing a custom analyzer for your projects, but it should be a reusable component that you can integrate into your development process once implemented. 这将需要为您的项目编写一个自定义分析器,但是它应该是可重用的组件,您可以在实现后将其集成到开发过程中。 The basic steps to resolve every function's type signature would be: 解决每个函数的类型签名的基本步骤是:
FSharpChecker
) instance. 创建一个F#类型检查器( FSharpChecker
)实例。 FSharpProjectOptions
). 加载您的项目选项( FSharpProjectOptions
)。 FSharpChecker.parseAndCheckFileInProject
). 解析并检查每个文件( FSharpChecker.parseAndCheckFileInProject
)。 FSharpCheckFileAnswer
). 从每个类型检查器结果( FSharpCheckFileAnswer
)中检索声明列表。 FSharpType
) for each declaration. 为每个声明打印类型签名( FSharpType
)。 Here's a quick solution I put together as a starting point: 这是我汇总的一个快速解决方案:
#r @"FSharp.Compiler.Service.25.0.1\lib\net45\FSharp.Compiler.Service.dll"
#r @"FSharp.Compiler.Service.ProjectCracker.25.0.1\lib\net45\FSharp.Compiler.Service.ProjectCracker.dll"
open Microsoft.FSharp.Compiler.SourceCodeServices
open System
open System.IO
type Namespace =
{
Name: string
XmlDoc: System.Collections.Generic.IList<string>
}
type Declaration =
| Namespace of Namespace * Declaration list
| Module of FSharpEntity * Declaration list
| Class of FSharpEntity * Declaration list
| Interface of FSharpEntity * Declaration list
| Enum of FSharpEntity * Declaration list
| Record of FSharpEntity * Declaration list
| Union of FSharpEntity * Declaration list
| Function of FSharpMemberOrFunctionOrValue
| Binding of FSharpMemberOrFunctionOrValue
let checker = FSharpChecker.Create(1, true)
let getProject projectFile =
ProjectCracker.GetProjectOptionsFromProjectFile(projectFile)
let private isNamespace (declaration: FSharpImplementationFileDeclaration) =
match declaration with
| FSharpImplementationFileDeclaration.Entity (entity, children) -> entity.IsNamespace
| _ -> false
let rec private getDeclaration nsSoFar (declaration: FSharpImplementationFileDeclaration) =
[
match declaration with
| FSharpImplementationFileDeclaration.Entity (entity, children) ->
if entity.IsNamespace then
if children.Length = 1 && children.Head |> isNamespace
then match nsSoFar with
| Some ns -> yield! getDeclaration (Some <| sprintf "%s.%s" ns entity.DisplayName) children.Head
| None -> yield! getDeclaration (Some entity.DisplayName) children.Head
else match nsSoFar with
| Some ns ->
let nsEntity = {Name = sprintf "%s.%s" ns entity.DisplayName; XmlDoc = entity.XmlDoc}
yield Namespace (nsEntity, children |> List.collect (getDeclaration nsSoFar))
| None ->
let nsEntity = {Name = entity.DisplayName; XmlDoc = entity.XmlDoc}
yield Namespace (nsEntity, children |> List.collect (getDeclaration nsSoFar))
elif entity.IsClass then
yield Class (entity, children |> List.collect (getDeclaration nsSoFar))
elif entity.IsInterface then
yield Interface (entity, children |> List.collect (getDeclaration nsSoFar))
elif entity.IsEnum then
yield Enum (entity, children |> List.collect (getDeclaration nsSoFar))
elif entity.IsFSharpModule then
yield Module (entity, children |> List.collect (getDeclaration nsSoFar))
elif entity.IsFSharpRecord then
yield Record (entity, children |> List.collect (getDeclaration nsSoFar))
elif entity.IsFSharpUnion then
yield Union (entity, children |> List.collect (getDeclaration nsSoFar))
else
()
| FSharpImplementationFileDeclaration.MemberOrFunctionOrValue (func, _, _) ->
if func.IsValCompiledAsMethod
then yield Function func
else yield Binding func
| _ -> ()
]
let getDeclarations (project: FSharpProjectOptions) file =
async {
let source = File.ReadAllText file
let! (parseResults, checkResults) = checker.ParseAndCheckFileInProject(file, 1, source, project)
return
match checkResults with
| FSharpCheckFileAnswer.Succeeded checkInfo ->
match checkInfo.ImplementationFile with
| Some implementation -> implementation.Declarations |> List.collect (getDeclaration None)
| None -> failwithf "No Implementation Available for File %s" file
| error -> failwithf "Error Checking File %s:\r\n%A" file error
}
let getDeclarationsForScript file =
async {
let source = File.ReadAllText file
let! (project, _) = checker.GetProjectOptionsFromScript(file, source)
return! getDeclarations project file
}
Then, if we have a sample script file called "Test.fsx" with a function like your example inside it ( let fi = sprintf "%d" i
), we can print the function's signature like so: 然后,如果我们有一个名为“ Test.fsx”的示例脚本文件,其中包含一个类似于您的示例的函数( let fi = sprintf "%d" i
),我们可以像下面这样打印该函数的签名:
let getTypeName (t: FSharpType) =
t.Format(FSharpDisplayContext.Empty).Replace("Microsoft.FSharp.Core.", "")
let rec printFunctionSignatures declarations =
for declaration in declarations do
match declaration with
| Namespace (_, ds) -> printFunctionSignatures ds
| Module (_, ds) -> printFunctionSignatures ds
| Function f -> f.FullType |> getTypeName |> printfn "%s: %s" f.DisplayName
| _ -> () // Handle all the other cases
getDeclarationsForScript "Test.fsx"
|> Async.RunSynchronously
|> printFunctionSignatures
This will pint out: 这将指出:
f: int -> string
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.