Giter VIP home page Giter VIP logo

fsharpapisearch's Introduction

FSharpApiSearch

F# API Search Engineはシグネチャや名前でF#のAPIを検索できる検索エンジンです。

プロジェクト一覧

プロジェクト名 概要
FSharpApiSearch 検索エンジン本体
FSharpApiSearch.Database 検索エンジンのデータベース作成ツール
FSharpApiSearch.Console 検索エンジンのフロントエンド(コンソールアプリケーション)

導入方法

リリースページからzipファイルをダウンロードし、展開してください。

使い方

まず最初にFSharpApiSearch.Database.exeを実行してデータベースを作成します。

FSharpApiSearch.Database.exe

デフォルトで検索できるアセンブリはFSharp.CoremscorlibSystemSystem.Coreです。 データベース作成時にアセンブリを指定すると検索対象を追加できます。--libオプションでアセンブリを検索するディレクトリを指定できます。 指定するアセンブリが依存するアセンブリも指定して下さい。

FSharpApiSearch.Database.exe --lib:TargetAssemblyDirectory TargetAssembly1 TargetAssembly2 DependentAssembly

FSharpApiSearch.Console.exeにクエリを与えずに実行するとインタラクティブモードで起動します。 インタラクティブモードを終了するには#qを入力してください。

FSharpApiSearch.Console.exe

引数にクエリを渡すと一度だけ検索を行います。

FSharpApiSearch.Console.exe "int -> int"

作成したデータベースを実際に検索で使用するには--targetオプションを使用します。

FSharpApiSearch.Console.exe --target:TargetAssembly1 --target:TargetAssembly2

--targetオプションを使用するとデフォルトのFSharp.CoremscorlibSystemSystem.Coreは検索対象に含まれなくなるため、 検索対象に含めたい場合は明示的に指定します。

FSharpApiSearch.Console.exe --target:TargetAssembly1 --target:TargetAssembly2 --target:FSharp.Core --target:mscorlib --target:System --target:System.Core

検索オプション

respect-name-differenceオプション

respect-name-differenceオプションが有効の場合は、クエリ中の異なる型変数や名前付きワイルドカードの名前の違いを検索に反映します。 異なる名前同士は同じ型にマッチしません。 例えば、?a -> ?aというクエリはint -> intというシグネチャにマッチしますが、?a -> ?bというクエリはint -> intにマッチしません。

このオプションに無効にした場合は、?a -> ?bというクエリでint -> intにマッチします。

greedy-matchingオプション

greedy-matchingオプションが有効の場合は、型変数と他の型がそれぞれマッチするようになり、一致度が高い順に並び替えられて表示されます。 また、検索に型制約が考慮されるようになります。

ignore-param-styleオプション

関数、メソッドの引数の形式には、カリー化形式(arg1 -> arg2 -> returnType)とタプル形式(arg1 * arg2 -> returnType)の2種類があります。 ignore-param-styleオプションが有効の場合は、カリー化形式とタプル形式を無視してマッチします。

ignore-caseオプション

ignore-caseオプションが有効の場合は、API名、型名とのマッチング時に大文字と小文字を区別しません。

substringオプション

substringオプションが有効の場合は、部分文字列で検索します。

swap-orderオプション

swap-orderオプションが有効の場合は、引数とタプルの順番を入れ替えて検索します。 例えば、a -> b -> cというクエリでb -> a -> cにマッチします。

complementオプション

complementオプションが有効の場合は、不足している引数とタプルの要素を補完して検索します。 例えば、a * cというクエリでa * b * cにマッチします。

single-letter-as-variableオプション

single-letter-as-variableオプションが有効の場合は、一文字の型名を型変数名として扱います。 例えば、t listというクエリは't listと同じです。

languageオプション

クエリ、検索、結果表示を、languageオプションで指定したプログラミング言語に切り替えます。 このオプションにはF# とC# を指定できます。

xmldocオプション

xmldocオプションが有効の場合は、検索結果にXMLドキュメントを表示します。

F#のクエリ仕様

F#のクエリは基本的にはF#のシグネチャと同じです。FSharpApiSearchの拡張のみ詳細を説明します。

> はFSharpApiSearch.Console.exeをインタラクティブモードで起動したときのプロンプトです。

検索可能なAPI

API クエリ例
モジュールの関数と値 int -> string
レコード、構造体のフィールド Ref<'a> -> 'a
判別共用体 'a -> Option<'a>
メンバー 'a list -> int
コンストラクター Uri : _
Uri.new : _
Uri..ctor : _
名前 (関数名、メンバー名等) head : 'a list -> 'a
head
アクティブパターン (||) : ... -> Expr -> ?
型、型略称、モジュール List<'T>
コンピュテーション式 { let! } : Async<'T>
サブタイプ検索 #seq<'a> -> 'a

名前検索

名前で検索するにはname : signatureまたはnameと書きます。シグネチャを指定しない場合は、シグネチャ部分に_を指定します。

> id : 'a -> 'a
Microsoft.FSharp.Core.Operators.id: 'T -> 'T, module value, FSharp.Core

> choose
Microsoft.FSharp.Collections.Array.Parallel.choose: ('T -> option<'U>) -> 'T[] -> 'U[], module value, FSharp.Core
Microsoft.FSharp.Collections.Array.choose: ('T -> option<'U>) -> 'T[] -> 'U[], module value, FSharp.Core
Microsoft.FSharp.Collections.List.choose: ('T -> option<'U>) -> list<'T> -> list<'U>, module value, FSharp.Core
Microsoft.FSharp.Collections.Seq.choose: ('T -> option<'U>) -> seq<'T> -> seq<'U>, module value, FSharp.Core
Microsoft.FSharp.Control.Event.choose: ('T -> option<'U>) -> IEvent<'Del, 'T> -> IEvent<'U>, module value, FSharp.Core
  when 'Del : delegate and 'Del :> Delegate
Microsoft.FSharp.Control.Observable.choose: ('T -> option<'U>) -> IObservable<'T> -> IObservable<'U>, module value, FSharp.Core

> choose : _
Microsoft.FSharp.Collections.Array.Parallel.choose: ('T -> option<'U>) -> 'T[] -> 'U[], module value, FSharp.Core
Microsoft.FSharp.Collections.Array.choose: ('T -> option<'U>) -> 'T[] -> 'U[], module value, FSharp.Core
Microsoft.FSharp.Collections.List.choose: ('T -> option<'U>) -> list<'T> -> list<'U>, module value, FSharp.Core
Microsoft.FSharp.Collections.Seq.choose: ('T -> option<'U>) -> seq<'T> -> seq<'U>, module value, FSharp.Core
Microsoft.FSharp.Control.Event.choose: ('T -> option<'U>) -> IEvent<'Del, 'T> -> IEvent<'U>, module value, FSharp.Core
  when 'Del : delegate and 'Del :> Delegate
Microsoft.FSharp.Control.Observable.choose: ('T -> option<'U>) -> IObservable<'T> -> IObservable<'U>, module value, FSharp.Core

アスタリスク(*)を使用すると部分一致検索ができます。 例えば、FSharp.Core.String.* : _FSharp.Core.Stringモジュールの全てのAPIを表示します。

> FSharp.Core.String.* : _
Microsoft.FSharp.Core.String.collect: (char -> string) -> string -> string, module value, FSharp.Core
Microsoft.FSharp.Core.String.concat: string -> seq<string> -> string, module value, FSharp.Core
Microsoft.FSharp.Core.String.exists: (char -> bool) -> string -> bool, module value, FSharp.Core
Microsoft.FSharp.Core.String.filter: (char -> bool) -> string -> string, module value, FSharp.Core
...

ワイルドカード

通常、'aなどの型変数とintなどの型名はマッチしません。 しかし、どちらのケースもまとめて検索したい場合があります。 このような場合に、ワイルドカード?または_が使えます。

> ? -> list<?> -> ?
Microsoft.FSharp.Collections.List.append: list<'T> -> list<'T> -> list<'T>, module value, FSharp.Core
Microsoft.FSharp.Collections.List.averageBy: ('T -> 'U) -> list<'T> -> 'U, module value, FSharp.Core
  when 'U : (static member op_Addition : 'U * 'U -> 'U) and 'U : (static member DivideByInt : 'U * int -> 'U) and 'U : (static member get_Zero : unit -> 'U)
Microsoft.FSharp.Collections.List.choose: ('T -> option<'U>) -> list<'T> -> list<'U>, module value, FSharp.Core
Microsoft.FSharp.Collections.List.chunkBySize: int -> list<'T> -> list<list<'T>>, module value, FSharp.Core
...

また、ワイルドカードに名前を付けることで、同じ名前を持つワイルドカードの位置には同一の型名が入るという条件を追加できます。 例えば、? -> ?は以下のすべての関数にマッチします。

  • 'a -> 'a
  • int -> int
  • 'a -> int
  • int -> string

しかし、?a -> ?aのように名前を付けると、上の例では'a -> intint -> stringにはマッチしなくなります。

サブタイプ検索

サブタイプ検索とは、指定した基本型またはインターフェイスと互換性のある型を指定する制約です。

クエリでサブタイプ検索を使用するには#typeと書きます。typeの部分には型名とインターフェイス名を指定できます。型名に型パラメータ、ワイルドカードは指定できません。

例えば、? -> #seq<'T>seq<'T>を継承したList<'T>IList<'T>'T[]等の型を返す関数を検索できます。

メンバー検索

インスタンスメンバー

インスタンスメンバーを検索するにはreceiver -> signatureと書きます。

メソッドを検索する場合はreceiver -> arg -> returnTypeと書きます。

多引数のメソッドを検索するにはreceiver -> arg1 -> arg2 -> returnTypeまたはreceiver -> arg1 * arg2 -> returnTypeと書きます。 通常ではメソッドの引数がタプル形式(arg1 * arg2)とカリー化形式(arg1 -> arg2)を区別せずに検索します。 引数の形式を区別して検索したい場合はignore-param-styleオプションを無効にします。

プロパティを検索する場合はreceiver -> propertyTypeと書きます。 インデックス付きプロパティはreceiver -> index -> propertyTypeと書きます。

静的メンバー

静的メンバーはモジュール内の値や関数と同じクエリで検索できます。多引数メソッドはインスタンスメソッドと同様にarg1 -> arg2 -> returnTypeまたはarg1 * arg2 -> returnTypeと書きます。

アクティブパターン

アクティブパターンを検索するには(||) : (args ->) inputType -> returnTypeと書きます。 パーシャルアクティブパターンを検索する場合は(|_|) : (args ->) inputType -> returnTypeと書きます。

inputTypeの部分にはアクティブパターンで扱う型を指定します。例えば、Exprに対するアクティブパターンを検索したい場合は(||) : ... -> Expr -> ?と書きます。

argsの部分にはアクティブパターンの引数を指定します。 引数があるアクティブパターンを検索したい場合は(||) : arg1 -> arg2 -> inputType -> returnTypeと書きます。 引数が無いアクティブパターンを検索したい場合は(||) : inputType -> returnTypeと書きます。 引数の有無を区別せず検索する場合は引数部分に...というキーワードを用いて、(||) : ... -> inputType -> returnTypeと書きます。

retyrnTypeの部分にはアクティブパターンの実態である関数が返す型を指定します。 アクティブパターン関数の戻り値は、ケースが1つ、複数、パーシャルアクティブパターンそれぞれで異なります。 対応する任意の型、option<_>Choice<_,...,_>を指定して下さい。 通常はワイルドカード(?)を使うことをお勧めします。

コンピュテーション式

コンピュテーション式を検索するには{ syntax } : typeと書きます。指定した構文と型を扱えるビルダーを検索します。

syntaxにはlet!yieldyield!returnreturn!useuse!if/thenforwhiletry/withtry/finallyと任意のカスタムオペレーション名を指定できます。 syntaxを複数指定する場合は;で区切り、{ s1; s2 } : typeと書きます。

C#のクエリ仕様

C#のクエリは、C#のシグネチャとは文法が異なります。

検索可能なAPI

API クエリ例
メンバー object -> () -> string
string -> int
コンストラクター Uri : _
Uri..ctor : _
型パラメーター List<T> -> int
Dictionary<tkey, tvalue>
<TKey, TValue> : Dictionary<TKey, TValue>
名前 (メンバー名等) Length : string -> int
Length
List
サブタイプ検索 <T> : #IEnumerable<T> -> T

名前検索

メンバーや型を名前で検索するにはname : signatureまたはnameと書きます。シグネチャを指定しない場合は、シグネチャ部分に_を指定します。

> Length : string -> int
System.String.Length : int, instance property with get, mscorlib

> Length
int Array.Length { get; }, instance property, mscorlib
int BitArray.Length { get; set; }, instance property, mscorlib
long BufferedStream.Length { get; }, instance property, mscorlib
long FileInfo.Length { get; }, instance property, mscorlib
...

> Length : _
int Array.Length { get; }, instance property, mscorlib
int BitArray.Length { get; set; }, instance property, mscorlib
long BufferedStream.Length { get; }, instance property, mscorlib
long FileInfo.Length { get; }, instance property, mscorlib
...

アスタリスク(*)を使用すると部分一致検索ができます。 例えば、System.String.* : _System.String型の全てのAPIを表示します。

> System.String.* : _
System.Array.Length : int, instance property with get, mscorlib
System.Collections.BitArray.Length : int, instance property with get set, mscorlib
System.ComponentModel.DataObjectFieldAttribute.Length : int, instance property with get, System
System.ComponentModel.MaskedTextProvider.Length : int, instance property with get, System
...

型パラメーター

型パラメーターの記述は次の3つがあります。

形式 型パラメーター 備考
<t> : signature <TKey, TValue> : Dictionary<TKey, TValue> TKey, TValue 冗長な形式で型パラメーターに大文字を使用できる
全て小文字 Dictionary<tkey, tvalue> tkey, tvalue 全て小文字の場合は<T>の部分を省略できる
一文字 List<T> -> int T 一文字の場合は<T>の部分を省略できる

ただし全て小文字の場合でもintやstring等の組み込み型は型パラメーターとして扱われません。

クエリの型パラメーター名は検索対象の型パラメーター名と一致している必要はありません。 例えば、List<A>というクエリはSystem.Collections.Generics.List<T>型とマッチします。

ワイルドカード

通常、Tなどの型パラメーターとintなどの型名はマッチしません。 しかし、どちらのケースもまとめて検索したい場合があります。 このような場合に、ワイルドカード?が使えます。

> <T> : List<T> -> ? -> int
System.Collections.Generic.List<T>.BinarySearch(T item) : int, instance method, mscorlib
System.Collections.Generic.List<T>.FindIndex(Predicate<T> match) : int, instance method, mscorlib
System.Collections.Generic.List<T>.FindLastIndex(Predicate<T> match) : int, instance method, mscorlib
System.Collections.Generic.List<T>.IndexOf(T item) : int, instance method, mscorlib
...

また、ワイルドカードに名前を付けることで、同じ名前を持つワイルドカードの位置には同一の型名が入るという条件を追加できます。 例えば、? -> ?は以下のすべてにマッチします。

  • static T F1<T>(T x)
  • static int F2 (int x)
  • static T F3<T>(int x)
  • static int F4 (string x)

しかし、?a -> ?aのように名前を付けると、上の例ではF2F4にはマッチしなくなります。

サブタイプ検索

サブタイプ検索とは、指定した基本型またはインターフェイスと互換性のある型を指定する制約です。

クエリでサブタイプ検索を使用するには#typeと書きます。typeの部分には型名とインターフェイス名を指定できます。型名に型パラメータ、ワイルドカードは指定できません。

例えば、<T> : ? -> #IEnumerable<T>IEnumerable<T>を継承したList<T>IList<T>T[]等の型を返すメソッドを検索できます。

メンバー検索

インスタンスメンバー

メソッドを検索する場合はreceiver -> (arg) -> returnTypeと書きます。 多引数のメソッドはreceiver -> (arg1, arg2) -> returnTypeと書きます。 引数部分の括弧は省略できます。引数または戻り値が無いAPIを検索したい場合は()voidを使用します。

> <T> : List<T> -> T -> int
System.Collections.Generic.List<T>.BinarySearch(T item) : int, instance method, mscorlib
System.Collections.Generic.List<T>.IndexOf(T item) : int, instance method, mscorlib
...

プロパティを検索する場合はreceiver -> propertyTypeと書きます。 インデックス付きプロパティはreceiver -> index -> propertyTypeと書きます。

> <T> : List<T> -> int
System.Collections.Generic.List<T>.Capacity : int, instance property with get set, mscorlib
System.Collections.Generic.List<T>.Count : int, instance property with get, mscorlib
...

静的メンバー

メソッドを検索する場合は(arg) -> returnTypeと書きます。 プロパティを検索する場合はpropertyTypeと書きます。

> string -> int
System.Convert.ToInt32(string value) : int, static method, mscorlib
System.Int32.Parse(string s) : int, static method, mscorlib
...

このように、メンバーが属する型は静的メンバーのクエリには記述しません。

FSharp.Compiler.Service の制限により対応できないAPI

  • C#で定義されたクラス、構造体のフィールド

動作環境

  • .Net Framework 4.5
  • F# 4.1

使用ライブラリ

fsharpapisearch's People

Contributors

bleis-tift avatar forki avatar gab-km avatar hafuu avatar magu701 avatar nosami avatar pocketberserker avatar wallymathieu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

fsharpapisearch's Issues

Static method of class

  • classからstatic method を抽出する
  • classからstatic peroperty, field は抽出しない
  • classからF# constructorを抽出する 'a -> SomeClass
  • classからC# constructorを抽出する 'a -> unit
  • 内部クラスからstatic methodを抽出する
  • 'a -> 'b -> 'c というクエリで検索する

Order by distance

'a and int : 1

int and int : 0

'a and 'x -> 'y: 2

ナドナド

初期化のパフォーマンス改善

アプリを実行して初期化が完了するまでに時間が(@hafuuの環境で3.0秒)掛かる。
並列化して短くできないだろうか?

計測方法

FSharpApiSearchClient.fsのコンストラクタにStopwatchを挟む。その後ReleaseビルドしたFSharpApiSearch.Consoleを実行する。

type FSharpApiSearchClient (targets: string seq, dictionaries: ApiDictionary seq) =
  let sw = System.Diagnostics.Stopwatch.StartNew()
  let targetAssemblies = dictionaries |> Seq.filter (fun x -> targets |> Seq.exists ((=)x.AssemblyName)) |> Seq.toList
  let apis = targetAssemblies |> Seq.collect (fun x -> x.Api) |> Seq.cache
  do apis |> Seq.iter (fun _ -> ())
  let abbreviationTable = dictionaries |> Seq.collect (fun x -> x.TypeAbbreviations) |> Seq.toList
  do sw.Stop(); printfn "%d [ms]" sw.ElapsedMilliseconds

試したこと

x.Apiの評価をアセンブリ毎に並列化してみた。2.2秒に短縮された。

type FSharpApiSearchClient (targets: string seq, dictionaries: ApiDictionary seq) =
  let sw = System.Diagnostics.Stopwatch.StartNew()
  let targetAssemblies = dictionaries |> Seq.filter (fun x -> targets |> Seq.exists ((=)x.AssemblyName)) |> Seq.toList
  let apis =
    targetAssemblies
    |> Seq.map (fun x -> async { return Seq.toArray x.Api })
    |> Async.Parallel
    |> Async.RunSynchronously
    |> Seq.collect id
    |> Seq.toArray
  let abbreviationTable = dictionaries |> Seq.collect (fun x -> x.TypeAbbreviations) |> Seq.toList
  do sw.Stop(); printfn "%d [ms]" sw.ElapsedMilliseconds

プロファイリング

ApiLoader.fsの317行目、FSharpEntity.MembersFunctionsAndValuesの呼び出しが遅いようだ。

Constraints of generic parameter

  • 制約を考慮したマッチング、制約をロード
    • Subtype constraints
      • 'a -> 'a というクエリで #seq<int> -> int というシグネチャをテストすると失敗するはず
    • Nullness constraints
    • Member constraints
    • Default constructor constraints
    • Value type constraints
    • Reference type constraints
    • Equality constraints
      • array
    • Comparison constraints
      • array
      • IntPtr, UIntPtr
    • and (テスト書く)
  • 対応しないがロードだけする
    • Enumeration constraints
    • Delegate constraints
    • Unmanaged constraints
  • C# の制約をロードできるかテストする
    • <A, B> when A : Bの挙動に注意する
  • QueryTypes.TupleSystem.Tupleとして振る舞う
  • 結果に制約を表示する

LINK: https://msdn.microsoft.com/ja-jp/library/dd233203.aspx

Searching scope

namespace, module, class...

Examples

System.* : _
List.* : _

Computation Expression

  • ある型に対応してる(っぽい)Builderクラスを探す
  • ある構文に対応している(っぽい)Builderクラスを探す

クエリ

query : { syntax-list } : type
syntax-list : syntax | syntax ; syntax-list
syntax : let! | do! ...
  • 検索
  • 結果に対応している構文一覧を出力する
  • CustomOperation

制限
#103 型拡張を使ったコンピュテーション式

Read C# Entities by System.Reflection

CompilerServiceではC#のフィールドを読み込めないのでリフレクションを使ってフィールドを読み込む

  • class
  • interface
  • constructor as static method
  • instance method
  • instance peroperty
  • instance field
  • static method
  • static property
  • static field
  • overloads
  • primitive type abbreviation (int, float ...)

ワイルドカードの検索を導入する

  • ? -> ? -> string引数を2つ受け取ってstringを返す関数
  • ?a -> ?a -> string同じ型の引数を2つ受け取ってstringを返す関数
  • 型名は型名、型変数は型変数同士でのみマッチするように変更する
  • 現在の挙動はオプション化
    • 型を固定したいときは!int!'a

検索結果が何か変

'a -> 'a で nativeptr<'T> -> 'T が出てくる
('a -> 'b) -> 'a option -> 'b option で Option.bind が出てくる
('a -> 'b option) -> 'a option -> 'b option で Option.map が出てくる

Search by function name

Search functions named map

map: _

Search functions named map and that has the signature

map: ('a -> 'b) -> 'a list -> 'b list

ActivePattern

intを受け取るActivePattern一覧とか取得できると嬉しい

FSharpApiSearch can search functions.

Examples

  1. 'a -> 'b
    • match
      • 'a -> string
      • 'a -> 'a
      • 'a -> int * int
      • int * int -> int
      • ('a -> 'b) -> 'c
      • ('a -> 'b)
      • 'a -> ('b -> 'c)
    • not match
      • 'a -> 'b -> 'c
      • 'a -> ('b -> 'c) -> 'd
  2. 'a -> string
    • match
      • 'a -> string
      • int -> string
    • not match
      • string -> int
      • 'a -> 'b
  3. 'a seq -> 'b
    • match
      • 'a seq -> 'a
      • 'a seq -> int
    • not match
      • 'a list -> 'a

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.