此有源图案与F#2.0编译:
let (|Value|_|) value = // 'a -> 'T option
match box value with
| :? 'T as x -> Some x
| _ -> None
但是,在F#3.0,发出错误:
主动模式 '|价值| _ |' 具有包含未由输入确定类型变量的结果类型。 所述常见的原因是[原文如此]当未提及的结果的情况下,例如, '让(| A | B |)(X:INT)= A X'。 这可以固定有类型约束,例如 '让(| A | B |)(X:INT):选择= A X'
我试过了:
let (|Value|_|) value : 'T option = ...
和:
let (|Value|_|) (value: 'U) = ...
怎样才可以解决吗?
环境:的Visual Studio 2012(RTM)和FSI v11.0.50727.1
编辑:这里有一个简单的摄制:
let (|X|) x = unbox x
有没有在F#2.0编译器在编译器做了不正确的分析和坏的代码生成与结果游离型变量一定的活动模式中的错误; 一个简单的摄制是
let (|Check|) (a : int) = a, None
//let (|Check|) (a : int) = a, (None : int option)
let check a =
match a with
| Check (10, None) -> System.Console.WriteLine "10"
| Check (20, None) -> System.Console.WriteLine "20"
check 10
check 20
其生成在编译时一个奇怪的警告和编译成看似不正确的代码。 我猜测,我们试图修复这个bug(并限制一些疯狂的情况下)在F#3.0也打破了一些法律代码修复的附带损害。
我将提交一份新的错误,但对于F#3.0,这听起来像你需要使用在其他的答案中提到的解决方法之一。
我没有安装新版本,但我同意这个看起来有点腥。 我猜有可能是这种限制一个很好的理由,但在其他问题你的例子似乎很compeling。
作为一种变通方法,我认为这将证人参数(即未被使用,但暗示什么结果的类型将是)可以工作:
let (|Value|_|) (witness:unit -> 'T) value : 'T option =
match box value with
| :? 'T as x -> Some x
| _ -> None
当然,这使得使用有点丑陋,因为你需要想出一些争论。 在上文中,我使用的类型的证人unit -> 'T
希望以下可能编译:
let witness () : 'T = failwith "!"
match box 1 with
| Value witness 1 -> printfn "one"
如果不工作,那么你或许可以尝试使用类型的见证参数'T
但你必须提供一个实际的功能,而不仅仅是一个普通的功能)。
为了完整,多了一个解决方法的缘故:
type Box<'R> = Box of obj
let (|Value|_|) ((Box x) : Box<'R> ) : 'R option =
match x with
| :? 'R as x -> Some x
| _ -> None
let check t =
match Box t with
| Value 1 -> printfn "one"
| Value 2 -> printfn "two"
check 1 // one
check 2 // two
但它仍然会遭受由@kvb中提到的问题的另一个线程 。 就个人而言,我会更喜欢使用参数活跃模式@ KVB的版本。
见我的回答你的其他问题,就如何解决这一问题,其中一个原因,这样的活动模式可能是不可取的一些想法。 我不知道该重大更改是否意。