簡體   English   中英

如何獲得F#簽名-Visual Studio或vs代碼

[英]how to get f# signature - visual studio or vs code

我希望能夠在我的代碼中顯式地編寫類型簽名。

VS代碼將(最終)生成某種重影簽名,但是我實際上想明確地采用這些生成的簽名並鍵入代碼。

有任何想法嗎? 我可以使用FSI,但這可能是一項繁瑣的技術。

理想情況下,我會右鍵單擊並“生成簽名”。盡管這並不總是適合人們的編碼風格,但我傾向於編寫代碼;

   let f : int -> string = 
      fun i -> i.ToString()

您可以使用Compiler Services SDK獲得F#函數的類型。 這將需要為您的項目編寫一個自定義分析器,但是它應該是可重用的組件,您可以在實現后將其集成到開發過程中。 解決每個函數的類型簽名的基本步驟是:

  1. 創建一個F#類型檢查器( FSharpChecker )實例。
  2. 加載您的項目選項( FSharpProjectOptions )。
  3. 解析並檢查每個文件( FSharpChecker.parseAndCheckFileInProject )。
  4. 從每個類型檢查器結果( FSharpCheckFileAnswer )中檢索聲明列表。
  5. 為每個聲明打印類型簽名( FSharpType )。

這是我匯總的一個快速解決方案:

#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
    } 

然后,如果我們有一個名為“ 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

這將指出:

f: int -> string

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM