首页 > 解决方案 > 无法识别的联合类型参数

问题描述

我在 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在函数体中将其识别为 a ,但在声明中没有?[|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)

标签: typesf#

解决方案


Digit不是类型。

ParsedItem是一个类型,但Digit不是,也不是Operator,AlphaNotParsed.

使用该语法,您定义了一个 type ParsedItem,其值可以有四种风格 - DigitOperatorAlphaNotParsed

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

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

在此示例中,item1item2都是 type 的值ParsedItem。它们不是不同类型的值。

如果你有一个 type 的值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,但您没有具体说明要为其他风格做什么。


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


推荐阅读