Roslyn analyzer, converted from C# to F# I'm learning F# and for an exercise, I took a roslyn analyzer in C# and ported it to F#.

In the excerpt below the GetParameterInfo function:  


takes in ArgumentSyntax which describes an argument passed to a
C# method at an invocation site.
And finds the corresponding IParameterSymbol which describes the method's parameter at the point in code where the method is defined.


Here it is:  

module UseNamedArgs.ParameterInfo

open System
open System.Collections.Immutable
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.CSharp.Syntax
open UseNamedArgs.CSharpAdapters
open UseNamedArgs.MaybeBuilder

type ParameterInfo = {
    MethodOrProperty : ISymbol;
    Parameter : IParameterSymbol }

type ISymbol with
    member symbol.GetParameters() =
        match symbol with
        | :? IMethodSymbol as s   -&gt; s.Parameters
        | :? IPropertySymbol as s -&gt; s.Parameters
        | _                       -&gt; ImmutableArray&lt;IParameterSymbol&gt;.Empty
        |&gt; Seq.toList

/// &lt;summary&gt;
/// To be able to convert positional arguments to named we need to find
/// corresponding &lt;see cref="IParameterSymbol" /&gt; for each argument.
/// &lt;/summary&gt;
type SemanticModel with
    member sema.GetParameterInfo (argument: ArgumentSyntax) =
        maybe {
            let argList = argument.Parent :?&gt; ArgumentListSyntax
            let exprSyntax = argList.Parent  :?&gt; ExpressionSyntax
            let methodOrProperty = sema.GetSymbolInfo(exprSyntax).Symbol
            let! parameters = methodOrProperty.GetParameters() |&gt; Option.ofList
            if isNull argument.NameColon then
                // A positional argument.
                match argList.Arguments.IndexOf(argument) with
                | index when index &gt;= 0 &amp;&amp; index &lt; parameters.Length -&gt; 
                    return { MethodOrProperty = methodOrProperty;
                             Parameter = parameters.[index] }
                | index when index &gt;= parameters.Length 
                             &amp;&amp; parameters.[parameters.Length - 1].IsParams -&gt;
                    return { MethodOrProperty = methodOrProperty;
                             Parameter = parameters.[parameters.Length - 1] }
                | _ -&gt; return! None
            else 
                // Potentially, this is a named argument.
                let! name = argument.NameColon.Name |&gt; Option.ofObj
                let! nameText = name.Identifier.ValueText |&gt; Option.ofObj
                // Yes, it's a named argument.
                let! parameter = parameters |&gt; Seq.tryFind (fun param -&gt; 
                    String.Equals(param.Name, 
                                  nameText, 
                                  StringComparison.Ordinal))

                return { MethodOrProperty = methodOrProperty;
                         Parameter = parameter }
}



The original C# code of this snippet was adapted from
CSharpEssentials
The maybe computational expression is defined in
MaybeBuilder
&mdash; but it's likely pretty much what you'd expect a maybe to be.


How can I change the code so it'll be more idiomatic F#?
And is it even anywhere in the ballpark of idiomatic F#?
I feel we can traverse the Roslyn AST but it's chatty and boring for write with a lot of non aspect code fragment :(

My suggestion for reference is my experimental project "F# Active pattern library for Roslyn Compiler Platform" can ease for use Roslyn AST directly F# pattern matching syntax.

https://github.com/kekyo/Microsoft.CodeAnalysis.ActivePatterns