Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Search F#文档是否有按函数类型搜索函数的方法?_Search_Documentation_F#_Types - Fatal编程技术网

Search F#文档是否有按函数类型搜索函数的方法?

Search F#文档是否有按函数类型搜索函数的方法?,search,documentation,f#,types,Search,Documentation,F#,Types,假设我想知道F#是否有类型为的库函数 ('T -> bool) -> 'T list -> int 也就是说,计算一个函数返回true的列表中有多少项。(或返回第一个返回true的项的索引) 在MSDN上的文档准备好之前,我曾经在MSR站点使用F#的大列表。我可以在页面上搜索上面的文本,因为类型已经列出。但是现在MSDN文档只列出了各个页面上的类型——模块页面是一堆描述性文本。谷歌有点工作,但它不能帮助 // compatible interfaces ('T -> b

假设我想知道F#是否有类型为的库函数

('T -> bool) -> 'T list -> int
也就是说,计算一个函数返回true的列表中有多少项。(或返回第一个返回true的项的索引)

在MSDN上的文档准备好之前,我曾经在MSR站点使用F#的大列表。我可以在页面上搜索上面的文本,因为类型已经列出。但是现在MSDN文档只列出了各个页面上的类型——模块页面是一堆描述性文本。谷歌有点工作,但它不能帮助

// compatible interfaces
('T -> bool) -> Seq<'T> -> int
// argument-swaps
Seq<'T> -> ('T -> bool) -> int
// type-variable names
('a -> bool) -> Seq<'a> -> int
// wrappers
('a -> bool) -> 'a list -> option<int>
// uncurried versions
('T -> bool) * 'T list -> int
// .NET generic syntax
('T -> bool) -> List<'T> -> int
// methods
List<'T> member : ('T -> bool) -> int
//兼容接口
('T->bool)->Seq->('T->bool)->int
//键入变量名
('a->bool)->Seq bool)->'a list->option
//未结婚版本
('T->bool)*'T list->int
//.NET通用语法
('T->bool)->列表成员:('T->bool)->int

Haskell为此有一个独立的程序,名为。F#是否有类似的工具,比如Fing之类的?

我不知道有这样的工具。不过,使用
System.Reflection
(或者更好,使用PowerPack中的元数据库)编写一个函数可能是一个有趣的练习,这样您就可以考虑等价模类型变量名等

编辑-我是对的-这是一个有趣的练习。下面的内容有很多缺点,但对于大约150行代码来说也不算太糟糕。希望这将足以让想要开发真正工具的人开始工作。它不做任何高级的事情,比如检查带有重排序参数的函数,元数据库对使用完全限定名有点挑剔,所以您需要小心一点。为了回答你原来帖子中的问题,我执行了

find "('a -> Microsoft.FSharp.Core.bool) -> Microsoft.FSharp.Collections.list`1<'a> -> Microsoft.FSharp.Core.int" 
其中,只有
List.findIndex
与您要查找的泛型类型完全相同,但如果类型参数组合正确,其他类型参数也一样(例如,如果
'a=int
List.find
具有所需的类型)。不幸的是,搜索中没有考虑约束,因此非
列表
函数实际上无法匹配

不用多说,下面是我使用的代码-您需要添加对FSharp.PowerPack.Metadata程序集的引用才能使其正常工作

open Microsoft.FSharp.Metadata
open System.Text.RegularExpressions

(* type parameters let us switch out representation if need be *)
type Tag<'ty> = | Tuple | Arr | Ground of 'ty
type Ty<'ty,'a> = Param of 'a | Complex of Tag<'ty> * Ty<'ty,'a> list

(* Gets something stable from an FSharpEntity so that we can see if two are identical *)
let rec getType (e:FSharpEntity) =
  if (e.IsAbbreviation) then
    getType e.AbbreviatedType.NamedEntity
  else
    e.ReflectionType

(* FSharpType -> Ty<System.Type,string> *)
let rec cvt (e:FSharpType) =
  if e.IsTuple then
    Complex(Tuple, e.GenericArguments |> Seq.map cvt |> List.ofSeq)
  elif e.IsFunction then
    Complex(Arr, e.GenericArguments |> Seq.map cvt |> List.ofSeq)
  elif e.IsGenericParameter then
    Param e.GenericParameter.Name
  else
    Complex(Ground(e.NamedEntity |> getType), e.GenericArguments |> Seq.map cvt |> List.ofSeq)

(* substitute type for variable within another type *)
let rec subst v t = function
| Complex(tag,l) -> Complex(tag, l |> List.map (subst v t))
| Param i when i = v -> t
| Param j -> Param j

(* get type variables used in a type *)
let rec usedVars = function
| Param i -> Set.singleton i
| Complex(tag, l) -> Set.unionMany (List.map usedVars l)

(* Find most general unifier (if any) for two types *)
let mgu t1 t2 =
  let rec mgu subs = function
  | [] -> Some subs
  | (Complex(tag1,l1),Complex(tag2,l2))::rest ->
       if tag1 <> tag2 then
         None
       else
         let rec loop r = function
         | [],[] -> mgu subs r
         | [],_ | _,[] -> None
         | x::xs, y::ys -> loop ((x,y)::r) (xs,ys)
         loop rest (l1,l2)
  | (Param i, Param j)::rest when i = j -> mgu subs rest
  | ((Param i, x) | (x, Param i))::rest ->
       if (Set.contains i (usedVars x)) then
         None (* type would be infinite when unifying *)
       else
         mgu ((i,x)::subs) (rest |> List.map (fun (t1,t2) -> (subst i x t1, subst i x t2)))
  mgu [] [t1,t2]

(* Active patterns for parsing - this is ugly... *)
let (|StartsWith|_|) r s =
  let m = Regex.Match(s, r)
  if m.Success && m.Index = 0 then
    Some(m.Value, s.Substring(m.Length))
  else None

let rec (|Any|) (|P|_|) = function
| P(x,Any (|P|_|) (l,r)) -> x::l, r
| s -> [],s

let rec (|Any1|_|) (|P|_|) = function
| P(x,Any (|P|_|) (l,r)) -> Some(x::l, r)
| _ -> None

let (|Seq|_|) (|P|_|) (|Q|_|) = function
| P(x,Q(y,r)) -> Some((x,y),r)
| _ -> None

let (|Choice|_|) (|P|_|) (|Q|_|) = function
| P(p) -> Some p
| Q(p) -> Some p
| _ -> None

let (|Delimit|_|) s (|P|_|) = function
| P(x,Any ((|Seq|_|) ((|StartsWith|_|) s) (|P|_|)) (l,r)) -> Some(x::(List.map snd l), r)
| _ -> None

let (|Delimit1|_|) s (|P|_|) = function
| P(x,StartsWith s (_,Delimit s (|P|_|) (l,r))) -> Some(x::l, r)
| _ -> None

(* Basically a BNF grammar for types *)
let rec (|TyE|_|) = function
| ArrE(p) | TupleE(p) | AtomE(p) -> Some(p)
| _ -> None
and (|ArrE|_|) = function
| Choice (|TupleE|_|) (|AtomE|_|) (dom,StartsWith "->" (_,TyE(rng,r))) -> Some(Complex(Arr,[dom;rng]), r)
| _ -> None
and (|TupleE|_|) = function
| Delimit1 @"\*" (|AtomE|_|) (l,r) -> Some(Complex(Tuple,l), r)
| _ -> None
and (|AtomE|_|) = function
| ParamE(x,r) | GroundE(x,r) | StartsWith @"\(" (_,TyE(x,StartsWith @"\)" (_,r))) -> Some(x,r)
| _ -> None
and (|ParamE|_|) = function
| StartsWith "'[a-zA-Z0-9]+" (s,r) -> Some(Param s, r)
| _ -> None
and (|GroundE|_|) = function
| StartsWith "[`.a-zA-Z0-9]+" (gnd, StartsWith "<" (_, Delimit "," (|TyE|_|) (l, StartsWith ">" (_,r)))) -> 
      let ty = FSharpAssembly.FSharpLibrary.GetEntity gnd |> getType
      Some(Complex(Ground(ty), l), r)
| StartsWith "[`.a-zA-Z0-9]+" (gnd, r) ->
      let ty = FSharpAssembly.FSharpLibrary.GetEntity gnd |> getType
      Some(Complex(Ground(ty), []), r)
| _ -> None

(* parse a string into a type *)
let parse (s:string) =
  (* remove whitespace before matching *)
  match s.Replace(" ","") with
  | TyE(ty,"") -> ty
  | _ -> failwith "Not a well-formed type"

(* an infinite stream of possible variable names - for performing renaming *)
let rec names = 
  let letters = ['a' .. 'z'] |> List.map string
  seq {
    yield! letters
    for n in names do
      for l in letters do
        yield n + l
  }

(* finds entities in the F# library with the requested signature, modulo type parameter unification *)
let find s =
  let ty = parse s
  let vars = usedVars ty
  seq {
    for e in FSharpAssembly.FSharpLibrary.Entities do
    for m in e.MembersOrValues do
      (* need try/catch to avoid error on weird types like "[]`1" *)
      match (try Some(cvt m.Type) with _ -> None) with
      | Some ty2 ->
        (* rename all type variables from the query to avoid incorrectly unifying with type variables in signatures *)
        let used = usedVars ty2
        let newVars = Seq.choose (fun v -> if Set.contains v used then None else Some(Param v)) names
        let varMap = Map.ofSeq (Seq.zip vars newVars)
        let ty = Map.fold (fun t v p -> subst v p t) ty varMap
        match mgu ty ty2 with
        | None -> ()
        | Some _ -> yield sprintf "%s.%s.%s" e.Namespace e.DisplayName m.DisplayName 
      | _ -> () }
打开Microsoft.FSharp.Metadata
打开System.Text.RegularExpressions
(*类型参数允许我们在需要时切换表示*)
类型标记*Ty列表
(*从FSharpEntity获取稳定的内容,以便我们可以查看两个实体是否相同*)
let rec getType(e:FSharpEntity)=
如果(例如,伊莎贝拉)那么
getType e.缩写类型.NamedEntity
其他的
e、 反射型
(*FSharpType->Ty*)
let rec cvt(e:FSharpType)=
如果e是整数,那么
复杂(元组,例如一般参数|>Seq.map cvt |>List.ofSeq)
伊里夫·e·伊斯函数
复杂(Arr,e.GenericalArguments |>Seq.map cvt |>List.of Seq)
elif e.IsGenericParameter然后
参数e.GenericParameter.Name
其他的
复杂(背景(例如NamedEntity |>getType),例如genericalarguments |>Seq.map cvt |>List.ofSeq)
(*用类型替换另一类型内的变量*)
设rec subst v t=函数
|Complex(tag,l)->Complex(tag,l |>List.map(subst v t))
|i=v->t时的参数i
|参数j->参数j
(*获取类型*中使用的类型变量)
让rec usedVars=函数
|参数i->Set.singleton i
|Complex(tag,l)->Set.unionMany(List.map usedVars l)
(*查找两种类型的最通用统一器(如有)*)
让mgu t1 t2=
设rec mgu subs=函数
|[]->一些潜艇
|(复数(tag1,l1),复数(tag2,l2))::rest->
如果tag1 tag2,则
没有一个
其他的
让rec循环r=函数
|[],[]->mgu接头r
|[],124; 124;,[]->无
|x::xs,y::ys->loop((x,y)::r)(xs,ys)
循环休息(l1、l2)
|(参数i,参数j)::i=j时静止->mgu SUB静止
|((参数i,x)|(x,参数i))::rest->
如果(Set.contains i(usedVars x)),则
None(*统一*时,类型将是无限的)
其他的
mgu((i,x)::subs)(rest |>List.map(fun(t1,t2)->(substixt1,substixt2)))
mgu[][t1,t2]
(*用于解析的活动模式-这很难看…*)
让(|开始与| |)r s=
设m=Regex.Match(s,r)
如果m.Success&&m.Index=0,则
一些(m.Value,s.Substring(m.Length))
没有别的
设rec(| Any |)(| P | | |)=函数
|P(x,Any(| P | | | |)(l,r))->x::l,r
|s->[],s
设rec(| Any1 | | | |)(| P | |)=函数
|P(x,Any(| P | | | |)(l,r))->一些(x::l,r)
|无
设(| Seq | | | | |)(| P | | |)(| Q | |)=函数
|P(x,Q(y,r))->一些((x,y,r)
|无
let(| Choice | | | | | | | | | |)(P | | | |)(Q | | |)=函数
|P(P)->一些P
|Q(p)->一些p
|无
设(|定界| | |)s(| P | | |)=函数
|P(x,Any(| Seq | | | | | | | |)s)(| P | | | | | | | | | | | |)s)(l,r))->一些(x:(List.map snd l),r)
|无
设(|定界1 | | |)s(| P | | |)=函数
|P(x,从s开始(|,定界s(| P | | | |))(l,r))->一些(x::l,r)
|无
(*基本上是类型的BNF语法*)
设rec(| TyE | |)=函数
|ArrE(p)| TupleE(p)| AtomE(p)->Some(p)
|无
and(| ArrE | | |)=函数
|选择(| TupleE | | | | | | | | | | | | | | | | |)(dom,StartsWith“->”(|,TyE(rng,r)))->一些(复杂的(Arr,[dom;rng]),r)
|无
and(| TupleE | |)=函数
|定界1@“\*”(|原子| | |)-(l,r)->一些(复数(元组,l),r)
|无
和(|原子| |)=函数
|参数(x,r)|地面(x,r)|带“\”(“(\uu,TyE(x,带“\”)”(\ur)))->一些(x,r)
|无
和(|参数| |)=函数
|以“'[a-zA-Z0-9]+”(s,r)->一些(参数s,r)开始
|无
and(| GroundE | | |)=函数
|带“[`.a-zA-Z0-9]+”的启动(接地,带“(`a-zA-Z0-9)))->
让ty=FSharpAssembly.FSharpLibrary.GetEntity gnd |>getType
一些(复杂的(地面(ty)、l、r)
|用“[`.a-zA-Z0-9]+”(接地,右)->
让ty=FSharpAssembly.FSharpLibrary.GetEntity gnd |>getType
一些(复杂的(地面(ty),[]),r)
|无
(*将字符串解析为类型*)
让我们分析(s:string)=
(*在匹配之前删除空白*
open Microsoft.FSharp.Metadata
open System.Text.RegularExpressions

(* type parameters let us switch out representation if need be *)
type Tag<'ty> = | Tuple | Arr | Ground of 'ty
type Ty<'ty,'a> = Param of 'a | Complex of Tag<'ty> * Ty<'ty,'a> list

(* Gets something stable from an FSharpEntity so that we can see if two are identical *)
let rec getType (e:FSharpEntity) =
  if (e.IsAbbreviation) then
    getType e.AbbreviatedType.NamedEntity
  else
    e.ReflectionType

(* FSharpType -> Ty<System.Type,string> *)
let rec cvt (e:FSharpType) =
  if e.IsTuple then
    Complex(Tuple, e.GenericArguments |> Seq.map cvt |> List.ofSeq)
  elif e.IsFunction then
    Complex(Arr, e.GenericArguments |> Seq.map cvt |> List.ofSeq)
  elif e.IsGenericParameter then
    Param e.GenericParameter.Name
  else
    Complex(Ground(e.NamedEntity |> getType), e.GenericArguments |> Seq.map cvt |> List.ofSeq)

(* substitute type for variable within another type *)
let rec subst v t = function
| Complex(tag,l) -> Complex(tag, l |> List.map (subst v t))
| Param i when i = v -> t
| Param j -> Param j

(* get type variables used in a type *)
let rec usedVars = function
| Param i -> Set.singleton i
| Complex(tag, l) -> Set.unionMany (List.map usedVars l)

(* Find most general unifier (if any) for two types *)
let mgu t1 t2 =
  let rec mgu subs = function
  | [] -> Some subs
  | (Complex(tag1,l1),Complex(tag2,l2))::rest ->
       if tag1 <> tag2 then
         None
       else
         let rec loop r = function
         | [],[] -> mgu subs r
         | [],_ | _,[] -> None
         | x::xs, y::ys -> loop ((x,y)::r) (xs,ys)
         loop rest (l1,l2)
  | (Param i, Param j)::rest when i = j -> mgu subs rest
  | ((Param i, x) | (x, Param i))::rest ->
       if (Set.contains i (usedVars x)) then
         None (* type would be infinite when unifying *)
       else
         mgu ((i,x)::subs) (rest |> List.map (fun (t1,t2) -> (subst i x t1, subst i x t2)))
  mgu [] [t1,t2]

(* Active patterns for parsing - this is ugly... *)
let (|StartsWith|_|) r s =
  let m = Regex.Match(s, r)
  if m.Success && m.Index = 0 then
    Some(m.Value, s.Substring(m.Length))
  else None

let rec (|Any|) (|P|_|) = function
| P(x,Any (|P|_|) (l,r)) -> x::l, r
| s -> [],s

let rec (|Any1|_|) (|P|_|) = function
| P(x,Any (|P|_|) (l,r)) -> Some(x::l, r)
| _ -> None

let (|Seq|_|) (|P|_|) (|Q|_|) = function
| P(x,Q(y,r)) -> Some((x,y),r)
| _ -> None

let (|Choice|_|) (|P|_|) (|Q|_|) = function
| P(p) -> Some p
| Q(p) -> Some p
| _ -> None

let (|Delimit|_|) s (|P|_|) = function
| P(x,Any ((|Seq|_|) ((|StartsWith|_|) s) (|P|_|)) (l,r)) -> Some(x::(List.map snd l), r)
| _ -> None

let (|Delimit1|_|) s (|P|_|) = function
| P(x,StartsWith s (_,Delimit s (|P|_|) (l,r))) -> Some(x::l, r)
| _ -> None

(* Basically a BNF grammar for types *)
let rec (|TyE|_|) = function
| ArrE(p) | TupleE(p) | AtomE(p) -> Some(p)
| _ -> None
and (|ArrE|_|) = function
| Choice (|TupleE|_|) (|AtomE|_|) (dom,StartsWith "->" (_,TyE(rng,r))) -> Some(Complex(Arr,[dom;rng]), r)
| _ -> None
and (|TupleE|_|) = function
| Delimit1 @"\*" (|AtomE|_|) (l,r) -> Some(Complex(Tuple,l), r)
| _ -> None
and (|AtomE|_|) = function
| ParamE(x,r) | GroundE(x,r) | StartsWith @"\(" (_,TyE(x,StartsWith @"\)" (_,r))) -> Some(x,r)
| _ -> None
and (|ParamE|_|) = function
| StartsWith "'[a-zA-Z0-9]+" (s,r) -> Some(Param s, r)
| _ -> None
and (|GroundE|_|) = function
| StartsWith "[`.a-zA-Z0-9]+" (gnd, StartsWith "<" (_, Delimit "," (|TyE|_|) (l, StartsWith ">" (_,r)))) -> 
      let ty = FSharpAssembly.FSharpLibrary.GetEntity gnd |> getType
      Some(Complex(Ground(ty), l), r)
| StartsWith "[`.a-zA-Z0-9]+" (gnd, r) ->
      let ty = FSharpAssembly.FSharpLibrary.GetEntity gnd |> getType
      Some(Complex(Ground(ty), []), r)
| _ -> None

(* parse a string into a type *)
let parse (s:string) =
  (* remove whitespace before matching *)
  match s.Replace(" ","") with
  | TyE(ty,"") -> ty
  | _ -> failwith "Not a well-formed type"

(* an infinite stream of possible variable names - for performing renaming *)
let rec names = 
  let letters = ['a' .. 'z'] |> List.map string
  seq {
    yield! letters
    for n in names do
      for l in letters do
        yield n + l
  }

(* finds entities in the F# library with the requested signature, modulo type parameter unification *)
let find s =
  let ty = parse s
  let vars = usedVars ty
  seq {
    for e in FSharpAssembly.FSharpLibrary.Entities do
    for m in e.MembersOrValues do
      (* need try/catch to avoid error on weird types like "[]`1" *)
      match (try Some(cvt m.Type) with _ -> None) with
      | Some ty2 ->
        (* rename all type variables from the query to avoid incorrectly unifying with type variables in signatures *)
        let used = usedVars ty2
        let newVars = Seq.choose (fun v -> if Set.contains v used then None else Some(Param v)) names
        let varMap = Map.ofSeq (Seq.zip vars newVars)
        let ty = Map.fold (fun t v p -> subst v p t) ty varMap
        match mgu ty ty2 with
        | None -> ()
        | Some _ -> yield sprintf "%s.%s.%s" e.Namespace e.DisplayName m.DisplayName 
      | _ -> () }
API signature                     Query example
Functions and values in modules   int -> string
Fields of records and structs     Ref<'a> => 'a
Methods and properties            'a list -> int or 'a list => int
Constructors                      string -> Uri
Names (function and method names) head : 'a list -> 'a
Active patterns                   (||) : ... -> Expr -> ?