无法识别的联合体类型参数

时间:2019-05-05 04:15:51

标签: types f#

我在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 个答案:

答案 0 :(得分:4)

Digit不是一种类型。

ParsedItem是一种类型,但Digit不是,OperatorAlphaNotParsed都不是

使用该语法,您定义了类型ParsedItem,其值可以有四种样式-DigitOperatorAlphaNotParsed

您可以通过指定要创建的风味以及风味所需的任何参数来创建ParsedItem类型的新值(在您的情况下,所有风味都有一个char参数),如下所示:

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

在此示例中,item1item2均为类型ParsedItem的值。它们是不同类型的 not 值。

如果您的值类型为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上进行了模式匹配,但没有具体说明对其他口味的处理方式。


现在,我不知道您要在这里实现什么,并且您的代码有点荒谬(出于上述原因),所以我能做的最好的事情就是解释您对语言语法的误解。如果您详细说明自己的实际目标,我也许可以建议一种正确的编码方式。

答案 1 :(得分:2)

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