Активный шаблон в FSharpPlus trySscanf

#f# #pattern-matching #active-pattern #f#

#f# #сопоставление с шаблоном #активный-шаблон #f#

Вопрос:

Я пытаюсь создать активный шаблон Scan вокруг FSharpPlus trySscanf , чтобы сработало следующее:

 let res = // res = 42
  match "Hello 42 World" with
  | Scan "Hello %i World" n -> n
 

Насколько я понимаю, неполные активные шаблоны работают, мне просто нужно вернуть параметр, trySscanf который уже возвращает параметр, поэтому я попробовал следующее:

 let (|Scan|_|) = trySscanf
 

Когда это не сработало, я попробовал более явный

 let (|Scan|_|) pattern input = trySscanf pattern input
 

Они оба завершаются ошибкой со следующей ошибкой компиляции:

 Type constraint mismatch when applying the default type 'obj' for a type inference variable. No overloads match for method 'TryParseArray'.
Known return type: (string [] -> obj option)
Known type parameters: < obj , Internals.TryParseArray >
Available overloads:
 - static member Internals.TryParseArray.TryParseArray :  ^t * obj -> (string [] ->  ^t option) when (Control.TryParse or  ^t) : (static member TryParse :  ^t * Control.TryParse -> (string ->  ^t option)) // Argument at index 1 doesn't match
 - static member Internals.TryParseArray.TryParseArray : ('t1 * 't2' * 't3 * 't4 * 't5 * 't6 * 't7) * Internals.TryParseArray -> (string [] -> ( ^a7 *  ^a8 *  ^a9 *  ^a10 *  ^a11 *  ^a12 *  ^a13) option) when (Control.TryParse or  ^a7) : (static member TryParse :  ^a7 * Control.TryParse -> (string ->  ^a7 option)) and (Control.TryParse or  ^a8) : (static member TryParse :  ^a8 * Control.TryParse -> (string ->  ^a8 option)) and (Control.TryParse or  ^a9) : (static member TryParse :  ^a9 * Control.TryParse -> (string ->  ^a9 option)) and (Control.TryParse or  ^a10) : (static member TryParse :  ^a10 * Control.TryParse -> (string ->  ^a10 option)) and (Control.TryParse or  ^a11) : (static member TryParse :  ^a11 * Control.TryParse -> (string ->  ^a11 option)) and (Control.TryParse or  ^a12) : (static member TryParse :  ^a12 * Control.TryParse -> (string ->  ^a12 option)) and (Control.TryParse or  ^a13) : (static member TryParse :  ^a13 * Control.TryParse -> (string ->  ^a13 option)) // Argument at index 1 doesn't match
 - static member Internals.TryParseArray.TryParseArray : ('t1 * 't2' * 't3 * 't4 * 't5 * 't6) * Internals.TryParseArray -> (string [] -> ( ^a6 *  ^a7 *  ^a8 *  ^a9 *  ^a10 *  ^a11) option) when (Control.TryParse or  ^a6) : (static member TryParse :  ^a6 * Control.TryParse -> (string ->  ^a6 option)) and (Control.TryParse or  ^a7) : (static member TryParse :  ^a7 * Control.TryParse -> (string ->  ^a7 option)) and (Control.TryParse or  ^a8) : (static member TryParse :  ^a8 * Control.TryParse -> (string ->  ^a8 option)) and (Control.TryParse or  ^a9) : (static member TryParse :  ^a9 * Control.TryParse -> (string ->  ^a9 option)) and (Control.TryParse or  ^a10) : (static member TryParse :  ^a10 * Control.TryParse -> (string ->  ^a10 option)) and (Control.TryParse or  ^a11) : (static member TryParse :  ^a11 * Control.TryParse -> (string ->  ^a11 option)) // Argument at index 1 doesn't match
 - static member Internals.TryParseArray.TryParseArray : ('t1 * 't2' * 't3 * 't4 * 't5) * Internals.TryParseArray -> (string [] -> ( ^a5 *  ^a6 *  ^a7 *  ^a8 *  ^a9) option) when (Control.TryParse or  ^a5) : (static member TryParse :  ^a5 * Control.TryParse -> (string ->  ^a5 option)) and (Control.TryParse or  ^a6) : (static member TryParse :  ^a6 * Control.TryParse -> (string ->  ^a6 option)) and (Control.TryParse or  ^a7) : (static member TryParse :  ^a7 * Control.TryParse -> (string ->  ^a7 option)) and (Control.TryParse or  ^a8) : (static member TryParse :  ^a8 * Control.TryParse -> (string ->  ^a8 option)) and (Control.TryParse or  ^a9) : (static member TryParse :  ^a9 * Control.TryParse -> (string ->  ^a9 option)) // Argument at index 1 doesn't match
 - static member Internals.TryParseArray.TryParseArray : ('t1 * 't2' * 't3 * 't4) * Internals.TryParseArray -> (string [] -> ( ^a4 *  ^a5 *  ^a6 *  ^a7) option) when (Control.TryParse or  ^a4) : (static member TryParse :  ^a4 * Control.TryParse -> (string ->  ^a4 option)) and (Control.TryParse or  ^a5) : (static member TryParse :  ^a5 * Control.TryParse -> (string ->  ^a5 option)) and (Control.TryParse or  ^a6) : (static member TryParse :  ^a6 * Control.TryParse -> (string ->  ^a6 option)) and (Control.TryParse or  ^a7) : (static member TryParse :  ^a7 * Control.TryParse -> (string ->  ^a7 option)) // Argument at index 1 doesn't match
 - static member Internals.TryParseArray.TryParseArray : ('t1 * 't2' * 't3) * Internals.TryParseArray -> (string [] -> ( ^a3 *  ^a4 *  ^a5) option) when (Control.TryParse or  ^a3) : (static member TryParse :  ^a3 * Control.TryParse -> (string ->  ^a3 option)) and (Control.TryParse or  ^a4) : (static member TryParse :  ^a4 * Control.TryParse -> (string ->  ^a4 option)) and (Control.TryParse or  ^a5) : (static member TryParse :  ^a5 * Control.TryParse -> (string ->  ^a5 option)) // Argument at index 1 doesn't match
 - static member Internals.TryParseArray.TryParseArray : ('t1 * 't2) * Internals.TryParseArray -> (string [] -> ( ^a2 *  ^a3) option) when (Control.TryParse or  ^a2) : (static member TryParse :  ^a2 * Control.TryParse -> (string ->  ^a2 option)) and (Control.TryParse or  ^a3) : (static member TryParse :  ^a3 * Control.TryParse -> (string ->  ^a3 option)) // Argument at index 1 doesn't match
 - static member Internals.TryParseArray.TryParseArray : Internals.Id<'t1> * Internals.TryParseArray -> (string [] -> Internals.Id< ^a1> option) when (Control.TryParse or  ^a1) : (static member TryParse :  ^a1 * Control.TryParse -> (string ->  ^a1 option)) // Argument at index 1 doesn't match
 - static member Internals.TryParseArray.TryParseArray : Tuple< ^t1> * Internals.TryParseArray -> (string [] -> Tuple< ^t1> option) when (Control.TryParse or  ^t1) : (static member TryParse :  ^t1 * Control.TryParse -> (string ->  ^t1 option)) // Argument at index 1 doesn't match
 - static member Internals.TryParseArray.TryParseArray : t: ^t * Internals.TryParseArray -> (string [] ->  ^t option) when  ^t : (member get_Item1 :  ^t ->  ^t1) and  ^t : (member get_Item2 :  ^t ->  ^t2) and  ^t : (member get_Item3 :  ^t ->  ^t3) and  ^t : (member get_Item4 :  ^t ->  ^t4) and  ^t : (member get_Item5 :  ^t ->  ^t5) and  ^t : (member get_Item6 :  ^t ->  ^t6) and  ^t : (member get_Item7 :  ^t ->  ^t7) and  ^t : (member get_Rest :  ^t ->  ^tr) and (Control.TryParse or  ^t1) : (static member TryParse :  ^t1 * Control.TryParse -> (string ->  ^t1 option)) and (Control.TryParse or  ^t2) : (static member TryParse :  ^t2 * Control.TryParse -> (string ->  ^t2 option)) and (Control.TryParse or  ^t3) : (static member TryParse :  ^t3 * Control.TryParse -> (string ->  ^t3 option)) and (Control.TryParse or  ^t4) : (static member TryParse :  ^t4 * Control.TryParse -> (string ->  ^t4 option)) and (Control.TryParse or  ^t5) : (static member TryParse :  ^t5 * Control.TryParse -> (string ->  ^t5 option)) and (Control.TryParse or  ^t6) : (static member TryParse :  ^t6 * Control.TryParse -> (string ->  ^t6 option)) and (Control.TryParse or  ^t7) : (static member TryParse :  ^t7 * Control.TryParse -> (string ->  ^t7 option)) and (Internals.TryParseArray or  ^tr) : (static member TryParseArray :  ^tr * Internals.TryParseArray -> (string [] ->  ^tr option)) // Argument 't' doesn't match
 - static member Internals.TryParseArray.TryParseArray : unit * Internals.TryParseArray -> (string [] -> unit) // Argument at index 1 doesn't match Consider adding further type constraintsF# Compiler(71)
 

Очевидно, что у trySscanf есть куча перегрузок, которые я не принимаю во внимание, и я не уверен, как это сделать.

Возможно ли то, что я пытаюсь сделать?


Интересно, что если я добавлю match выражение, ошибка компиляции исчезнет, однако я могу использовать только PrintfFormat первый случай совпадения, который я пытаюсь:

 let parseLine line =
    match line with
    | Scan "mem[%i] = %i" (address, value) -> Op address value
    | Scan "mask = %s" str -> Mask str
 

Последняя строка сигнализирует об ошибке:

 This expression was expected to have type
    'int * int'    
but here has type
    'string'    (F# Compiler(1))
 

Ответ №1:

Вы просто забыли объявить свою функцию inline , сделайте это, и она будет работать просто отлично:

 #r "nuget: FSharpPlus"

open FSharpPlus

let inline (|Scan|_|) pattern input = trySscanf pattern input


let res48 =
  match "Hello 42 6 World" with
  | Scan "Hello %i World" n -> n
  | Scan "Hello %i %i World" (n1, n2) -> n1   n2
 

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