Нераспознанный аргумент типа объединения - PullRequest
0 голосов
/ 05 мая 2019

У меня есть следующие функции объединения и помощники в F #:

type ParsedItem =
    | Digit of char
    | Operator of char
    | Alpha of char
    | NotParsed of char

let private digits = ['0'..'9']@['.']
let private opers = ['!';'%';'^';'*';'(';')';'+';'=';'<';'>']
let private alphas =['A'..'Z']@['a'..'z']

let (|IsDigitChar|_|) ch =
    match List.exists(fun a->a=ch) digits with
    | true -> Some IsDigitChar
    | _ -> None

let (|IsOperChar|_|) ch =
    match List.exists(fun a->a=ch) opers with
    | true -> Some IsOperChar
    | _ -> None

let (|IsAlphaChar|_|) ch =
    match List.exists(fun a->a=ch) alphas with
    | true -> Some IsAlphaChar
    | _ -> None

let parseChar ch =
    match ch with
    | IsDigitChar -> Digit(ch)
    | IsOperChar -> Operator(ch)
    | IsAlphaChar -> Alpha(ch)
    | _ -> NotParsed(ch)

Но тип "Цифра" не распознается в следующей функции:

let coalesceDigits (dgts: Digit list) =  
    [|for Digit d in dgts -> d|] |> string

Поскольку компилятор выдает следующее предупреждение для аргумента (dgts: Digit list): The type 'Digit' is not defined'

Однако он также выдает следующее предупреждение для Digit d в теле функции [|for Digit d in ...: Incomplete pattern matches on this expression. For example, the value 'Alpha (_)' may indicate a case not covered by the pattern(s). Так что он распознает его как ParsedItem в теле, но не в объявлении?

Как заставить компилятор распознавать, что Digit действительно является типом, не объявляя его вне ParsedItem, или я должен объявить Digit и другие как их собственный тип, а затем добавить их к ParsedItem как следует?

type Digit = Digit of char
[...]
type ParsedItem =
    | Digit of Digit
    | Operator of Operator
    | ... (etc)

Ответы [ 2 ]

4 голосов
/ 05 мая 2019

Digit не тип.

ParsedItem является типом, но Digit - нет, и также не являются Operator, Alpha и NotParsed.

Используя этот синтаксис, вы определили тип ParsedItem, значения которого могут быть четырех видов: Digit, Operator, Alpha или NotParsed.

Вы можете создать новые значения типа ParsedItem, указав, какой аромат вы хотите создать, и любые параметры, которые требует аромат (в вашем случае все вкусы имеют один char параметр), например:

let item1 = Digit 'a'
let item2 = Operator 'b'
// and so on

В этом примере значения item1 и item2 являются значениями типа ParsedItem. Это не значения разных типов.

Если у вас есть значение типа ParsedItem, вы можете выяснить, какой это вкус, сопоставив шаблон:

let whatIsIt item =
    match item with
    | Digit c -> "It's a digit!"
    | Operand c -> "It's an operand!"
    | Alpha c -> "It's an alpha!"
    | NotParsed c -> "Not parsed :-/"

printfn "%s" (whatIsIt item1) // prints "It's a digit!"
printfn "%s" (whatIsIt item2) // prints "It's an operator!"

Если при написании сопоставления с образцом вы пропустите аромат, компилятор поймает вас:

let whatIsIt item =
    match item with
    | Digit c -> "It's a digit!"
    // Warning: incomplete pattern match

С этим предупреждением компилятор говорит вам: «Я вижу, вы определили, что делать, если item окажется Digit, но что я должен делать с остальными тремя разновидностями?»

Это то, что происходит и в вашем коде: вы сопоставляете шаблон с Digit d, но вы не указали, что делать с другими вариантами.


Теперь я не знаю, чего вы здесь добиваетесь, и ваш код выглядит бессмысленным (по причинам, описанным выше), поэтому лучшее, что я могу сделать, это объяснить, что вы неправильно понимаете в синтаксисе языка. Если вы уточните свою реальную цель, я могу предложить правильный способ ее кодирования.

2 голосов
/ 05 мая 2019

Digit не является типом, это тег / регистр типа ParsedItem

Таким образом, вам необходимо явно создать тип Digit и использовать его в теге Digit из ParsedItem.Компилятор знает, как это различить, поэтому одноименное имя Digit не проблема.

type Digit = DigitValue of char
type ParsedItem =
    | Digit of Digit ...
let coalesceDigits (dgts: Digit list) =  
    [|for (DigitValue d) in dgts -> d|] |> string
...