在F#中的序列表达式中输入推理 [英] Type inference in sequence expressions in F#
问题描述
我认为我不太了解F#如何在序列表达式中推断类型,以及即使直接从seq指定元素的类型,为什么类型不能正确识别。
在下面的F#代码中,我们有一个基类A和两个派生类B和C:
type A (x)=
成员aX = x
类型B(x)=
继承A(x)
类型C(x)=
继承A(x)
如果我试图以简单的顺序屈服它们的实例表达式,我得到两个错误:
//不起作用,但它是有道理的。
let testSeq = seq {
yield A(0)
yield B(1)//错误,预期类型:A
yield C(2)//错误,预期类型:A
}
这可能是有道理的,因为它可能不那么微不足道常见类型(接口,我认为可以使这个工作更加困难)。但是,这些错误可以通过安全的转换来解决:
//正常工作:)
let testSeqWithCast = seq {
收益率A(0)
收益率B(1):> A
收益C(2):> A
}
如果我不想使用强制转换?我尝试直接从seq中指定序列类型,但似乎并不奏效:
//应该可以工作,我想...
let testGenSeq = seq< A> {
yield A(0)
yield B(1)//错误,预期类型:A
yield C(2)
}
所以,我的问题是:有没有办法避免强制转换?如果没有,是否有一个原因,甚至指定类型不会使代码工作?
我试着通过以下链接挖掘:
http://msdn.microsoft.com/zh-CN/library/dd233209 .aspx
http:// lorgonblog .wordpress.com / 2009/10/25 / overview-of-type-inference-in-f /
但我没有发现任何用处......
预先感谢您提供的任何答案:
为了理解混淆的原因,你不应该再去任何地方,比第一条语句您提到的链接:
序列是一系列逻辑元素全部一种类型。
您可以返回一系列仅一个,相同类型,如 seq
或 SEQ<物镜>
。 OOP的事实是,类型 B
和 C
是从 A
不相关。以下可能会有所帮助:您的所有实例也都从 obj
继承,但为了使它们成为 seq< obj>
你应该明确施放:
//正常工作
let testSeq = seq< obj> {
产量A(0):> obj
收益率B(1):> obj
收益率C(2):> obj
}
或者只是框
他们就像下面:
//可以正常工作
let testSeq = seq {
yield box( A(0))
收益框(B(1))
收益框(C(2))
}
编辑:为了理解F#中显式转换的原因,以下(简单化)考虑可能会有所帮助。类型推断不会猜测;除非它可以确定性地派生 seq
类型,或者明确声明它,否则会抱怨。
如果你只是做
let testSeq = seq {
yield A(0)
yield B(1)
产量C(2)
}
编译器带有不确定性 - testSeq
可以是 seq
或 seq
,所以它抱怨。当你做
let testSeq = seq {
yield A(0)
yield upcast B(1 )
产生upcast C(2)
}
它推断<$ c根据第一个成员的类型将$ c> testSeq 作为 seq ,并将B和C上传到
A
没有抱怨。同样的,如果你这样做的话
let testSeq = seq {
yield box A(0)
yield upcast B(1)
收益率上升C(2)
}
根据第一个成员上次播放的类型推断 testSeq
为 seq< obj>
code> obj ,而不是 A
。
I think I do not quite understand how F# infers types in sequence expressions and why types are not correctly recognized even if I specify the type of the elements directly from "seq".
In the following F# code we have a base class A and two derived classes, B and C:
type A(x) =
member a.X = x
type B(x) =
inherit A(x)
type C(x) =
inherit A(x)
If I try to "yield" their instances in a simple sequence expressions, I get two errors:
// Doesn't work, but it makes sense.
let testSeq = seq {
yield A(0)
yield B(1) // Error, expected type: A
yield C(2) // Error, expected type: A
}
That can make sense, since it may not be so trivial to infer "common" types (interfaces, I think, can make that work far harder). However, those errors can be fixed with a safe cast:
// Works fine :)
let testSeqWithCast = seq {
yield A(0)
yield B(1) :> A
yield C(2) :> A
}
What if I do not want to use casts? I tried to specify the sequence type directly from "seq", but things do not seem to work:
// Should work, I think...
let testGenSeq = seq<A> {
yield A(0)
yield B(1) // Error, expected type: A
yield C(2)
}
So, my question is: is there a way to avoid casts? If not, is there a reason why even specifying the type doesn't make the code work?
I tried digging through following links:
http://msdn.microsoft.com/en-us/library/dd233209.aspx http://lorgonblog.wordpress.com/2009/10/25/overview-of-type-inference-in-f/
But I found nothing useful...
Thank you in advance for any kind of answer you can give :)
In order to understand the cause of your confusion you should not go anywhere further, than the first statement of the link you referred to :
A sequence is a logical series of elements all of one type.
You can return a sequence of only one, the same type like seq<A>
, or seq<obj>
. The OOP-ish fact that types B
and C
are inherited from A
is not relevant. The following may help: all your instances are also inherited from obj
, but in order to make from them a seq<obj>
you should explicitly cast:
// Works fine
let testSeq = seq<obj> {
yield A(0) :> obj
yield B(1) :> obj
yield C(2) :> obj
}
or just box
them like below:
// Works fine too
let testSeq = seq {
yield box (A(0))
yield box (B(1))
yield box (C(2))
}
EDIT: For understanding the reasoning behind explicit casting in F# the following (simplistic) consideration may help. Type inference does not do guessing; unless it can derive seq
type deterministically, or have it explicitly declared, it will complain.
If you just do
let testSeq = seq {
yield A(0)
yield B(1)
yield C(2)
}
compiler is presented with indeterminism - testSeq
can be either seq<A>
, or seq<obj>
, so it complains. When you do
let testSeq = seq {
yield A(0)
yield upcast B(1)
yield upcast C(2)
}
it infers testSeq
as seq<A>
based on type of the first member and upcasts B and C to A
without complaining. Similarly, if you do
let testSeq = seq {
yield box A(0)
yield upcast B(1)
yield upcast C(2)
}
it will infer testSeq
as seq<obj>
based on the type of the first member upcasting this time second and third members to obj
, not A
.
这篇关于在F#中的序列表达式中输入推理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!