使用DU(Discriminated Union类型),如何执行类型测试模式匹配? 我有以下运行代码:
type IU =
|Int of int
|Unit of Unit
let x = IU.Int(3)
let y = IU.Unit(())
let z = [3.14]
let showI (v) =
match box v with
| :? IU ->
match v with
| Int(_) -> "an IU int"
|_ -> "not a IU.int"
|_ -> "not a IU.int"
但是我对showI函数中的内部匹配不满意。我更喜欢这样的东西:
let showI (v) =
match box v with
| :? IU.Int -> "an int"
|_ -> "not a IU.int"
没有编译(错误:未定义Int类型)。
我错过了明显的语法吗?感谢。
注意:showI函数接受具有未知类型的变量;这就是臭盒v。
的原因答案 0 :(得分:5)
正如其他人所指出的,我不认为有任何内置的语言功能可以让你这样做。但是,您可以定义执行类型测试的active pattern:
let (|IsIU|_|) (candidate : obj) =
match candidate with
| :? IU as iu -> Some iu
| _ -> None
此活动模式的类型为obj -> IU option
。
您可以使用标准模式构建自己的自定义活动模式,如下所示:
let showI = function
| IsIU (IU.Int i) -> "an IU int"
| _ -> "not a IU.int"
在此示例中,自定义IsIU
活动模式由标准标识符模式组成,该模式与IU.Int
大小写匹配。
这是一个示例FSI会话,显示OP中给出的x
,y
和z
值的使用情况:
> showI x;;
val it : string = "an IU int"
> showI y;;
val it : string = "not a IU.int"
> showI z;;
val it : string = "not a IU.int"
答案 1 :(得分:1)
保持在您的问题的上下文中我相信您缺少的是IU.Int
不是类型,而是案例 Int
歧视联合类型 IU
。当你写
let x = IU.Int(3)
值x
的类型为IU
,而不是IU.Int
。这就是为什么编译器会因您尝试将obj
与UI.Int
与:?
模式匹配而咆哮。
在更广泛的背景下,您似乎尝试接近Javascript类型的F#a-la动态语言,但事实并非如此。夸大一点,你似乎尝试使用仅对一种类型obj
的参数进行操作的函数,因此花费大量的运行时间来动态发现特定的参数类型,并在途中犯错误的广泛机会。
这种方法错过了F#惯用DU用例的全部内容,即通过模式匹配机制将已知静态类型为IU
的值分解为特定的工会案例(IU.Int
或IU.Unit
):
let showI (v : IU) = // explicit argument type is added to illuminate the point
match v with
| IU.Int(x) -> sprintf "a IU.Int(%i) value" x
| _ -> "a IU.Unit"
因此,如果您错误地尝试使用不属于showI
类型的参数调用IU
,编译器将立即捕获错误类型参数的错误使用函数,并且不会构建代码的可执行形式,直到错误得到纠正。
编辑:除了惯用法之外,你可以在match
后卫的帮助下躲过一个when
,就像在下面的片段中一样,尽管这是讨厌的黑客:
open Microsoft.FSharp.Reflection
let showI (v) =
match box v with
| :? IU as x when (fst(FSharpValue.GetUnionFields(x, typeof<IU>))).Name.Equals("Int")
-> "an IU.Int"
| _ -> "not an IU.Int"