Документация F# имеет способ искать функции их типами?

Скажите, что я хочу знать, имеет ли F# библиотечную функцию типа

('T -> bool) -> 'T list -> int

т.е., что-то, что рассчитывает, сколько объектов списка, для которого функция возвращает true. (или возвращает индекс первого объекта, который возвращает true),

Я раньше использовал большой список на сайте MSR для F#, прежде чем документация относительно MSDN была готова. Я мог просто искать страницу вышеупомянутый текст, потому что типы были перечислены. Но теперь документация MSDN только перечисляет типы на отдельных страницах - страница модуля является шумами описательного текста. Google своего-рода-sorta работает, но он не может помочь с

// 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
// uncurried versions
('T -> bool) * 'T list -> int
// .NET generic syntax
('T -> bool) -> List<'T> -> int
// methods
List<'T> member : ('T -> bool) -> int

У Haskell есть автономная программа для названного Hoogle. F# имеет эквивалент, как Fing или что-то?

19
задан Nathan Shively-Sanders 12 February 2010 в 17:26
поделиться

2 ответа

На основании ответа kvb я создал полное приложение. Он размещен на github по адресу http://github.com/sandersn/fing .

Код все еще довольно уродливый, но он работает для простых случаев.На данный момент я убрал самый общий унификатор kvb ( mgu ), потому что он добавляет много неочевидных результатов. Такие причудливые вещи, как структурные ограничения и самый общий супертип, тоже пока не работают.

Есть также двоичный файл для версии для командной строки, если вы не хотите собирать из исходников. (Тем не менее, для этого по-прежнему требуется установленная современная версия среды выполнения .NET.) В конце концов я найду какой-нибудь хостинг ASP.NET, изучу ASP и оберну все это в веб-приложение, так что установка не потребуется вообще. (Думаю, если есть спрос, я мог бы создать графический интерфейс на стороне клиента, но у меня еще меньше опыта в подобных вещах.)

10
ответ дан 30 November 2019 в 03:59
поделиться

Мой вопрос заключается в том, как я могу манипулировать этими данными? Вставить только что «комментарий» затем иметь «задание» который вытягивает этот комментарий и подключает в функцию, которая обрабатывает его?

Точно.

Публикация обновлений состояния на страницах Facebook, вероятно, не связана с постановкой сообщений в очередь - я на самом деле не знаю их конкретного дизайна, но я думаю, что обновленные данные просто предоставляются по запросу через запрос, когда пользователи загружают свои страницы. (Если у Facebook нет отдельного процесса для денормализации данных обновления состояния.) 1

Напротив, отправка уведомлений об обновлении состояния по электронной почте является отличным кандидатом для организации очередей сообщений.

Типичная реализация предполагает запись нового сообщения (как правило, минимального, возможно, только вашего идентификатора пользователя) в определенную очередь сообщений - возможно, в очередь «EmailStartStartNotifications».

Затем другой процесс удаляет сообщения из очереди и точно знает, что с ними делать. Процесс, предназначенный для отправки сообщений электронной почты с обновлением состояния, будет использовать идентификатор пользователя (содержимое сообщения) для загрузки текущего состояния и списка адресов электронной почты друзей, создания и отправки сообщений электронной почты.

1 Оказалось, что вы можете найти много хорошей информации об архитектуре Facebook в Почему Facebook, Digg и Twitter так трудно масштабировать? с высокой масштабируемостью.

-121--4435040-

Существует некоторое программное обеспечение (Microsoft Dynamics), которое не позволит использовать отрицательные ключи в целочисленных полях размером более 2 байт. Кроме того, я не вижу причин ограничивать столбец идентификации положительными числами, когда столбец не используется в качестве внешнего идентификатора. т.е. идентификатор клиента

-121--3941978-

Я не знаю ни одного такого инструмента. Тем не менее, это может быть интересным упражнение, чтобы написать его с помощью System.Reflection (или даже лучше, библиотека метаданных в PowerPack), чтобы вы могли принять эквивалентность по модулю имена переменных типа и т.д.

EDIT - Я был прав - это было веселое упражнение. Что следует имеет много бородавок, но не слишком плохо для ~ 150 строк кода. Надеюсь, этого будет достаточно, чтобы начать работу с кем-то, кто хочет работать над настоящим инструментом. Он не делает ничего расширенного, как проверка на наличие функций с переупорядоченными параметрами, а библиотека метаданных немного заботится об использовании полных имен, поэтому нужно быть немного осторожным. Чтобы ответить на вопрос в вашей первоначальной записи, я выполнил

find "('a -> Microsoft.FSharp.Core.bool) -> Microsoft.FSharp.Collections.list`1<'a> -> Microsoft.FSharp.Core.int" 

и получил следующий список кандидатов:

Microsoft.FSharp.Core.Operators.( + )
Microsoft.FSharp.Core.Operators.( - )
Microsoft.FSharp.Core.Operators.( * )
Microsoft.FSharp.Core.Operators.( / )
Microsoft.FSharp.Core.Operators.( % )
Microsoft.FSharp.Core.Operators.sqrt
Microsoft.FSharp.Core.LanguagePrimitives.EnumOfValue
Microsoft.FSharp.Core.LanguagePrimitives.EnumToValue
Microsoft.FSharp.Core.LanguagePrimitives.AdditionDynamic
Microsoft.FSharp.Core.LanguagePrimitives.CheckedAdditionDynamic
Microsoft.FSharp.Core.LanguagePrimitives.MultiplyDynamic
Microsoft.FSharp.Core.LanguagePrimitives.CheckedMultiplyDynamic
Microsoft.FSharp.Core.LanguagePrimitives.GenericZero
Microsoft.FSharp.Core.LanguagePrimitives.GenericOne
Microsoft.FSharp.Collections.List.find
Microsoft.FSharp.Collections.List.findIndex
Microsoft.FSharp.Collections.List.maxBy
Microsoft.FSharp.Collections.List.minBy

Из них только List.findIndex имеет именно тот общий тип, который вы ищете, но с правильной комбинацией параметров типа так делают и другие (например, если 'a = int то List.find имеет нужный тип). К сожалению, ограничения не учитываются при поиске, поэтому функции списка , отличные от , фактически не могут совпадать.

Без дополнительной информации, вот код, который я использовал - вам нужно добавить ссылку на FSharp.PowerPack.Сборка метаданных для ее работы.

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 
      | _ -> () }
17
ответ дан 30 November 2019 в 03:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: