Pau*_*rth 9 .net c# ienumerable
在C#中实现一个基本的Scheme解释器时,我惊恐地发现了以下问题:
IEnumerator没有克隆方法!(或者更确切地说,IEnumerable不能为我提供"可克隆"枚举器).
我想要的是什么:
interface IEnumerator<T>
{
bool MoveNext();
T Current { get; }
void Reset();
// NEW!
IEnumerator<T> Clone();
}
Run Code Online (Sandbox Code Playgroud)
我无法想出IEnumerable的实现,它无法提供有效的可克隆IEnumerator(向量,链表等等)所有能够提供IEnumerator的克隆()的简单实现,如上所述...它会比提供Reset()方法更容易!).
缺少Clone方法意味着枚举序列的任何功能/递归习惯用法都不起作用.
这也意味着我无法"无缝地"使IEnumerable的行为像Lisp"列表"(为此你使用car/cdr递归枚举).即唯一的实现"(cdr some IEnumerable)"将是非常低效的.
任何人都可以建议一个现实的,有用的IEnumerable对象的例子,它无法提供有效的"Clone()"方法吗?是否存在"收益"构造的问题?
任何人都可以建议解决方法?
Dan*_*ker 23
逻辑是不可阻挡的!IEnumerable不支持Clone,你需要Clone,所以你不应该使用IEnumerable.
或者更准确地说,您不应该将它作为Scheme解释器工作的基础.为什么不做一个简单的不可变链表呢?
public class Link<TValue>
{
private readonly TValue value;
private readonly Link<TValue> next;
public Link(TValue value, Link<TValue> next)
{
this.value = value;
this.next = next;
}
public TValue Value
{
get { return value; }
}
public Link<TValue> Next
{
get { return next; }
}
public IEnumerable<TValue> ToEnumerable()
{
for (Link<TValue> v = this; v != null; v = v.next)
yield return v.value;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,该ToEnumerable方法使您可以方便地使用标准C#方式.
回答你的问题:
任何人都可以建议一个现实的,有用的IEnumerable对象的例子,它无法提供有效的"Clone()"方法吗?是否存在"收益"构造的问题?
IEnumerable可以在世界上任何地方获取其数据.这是一个从控制台读取行的示例:
IEnumerable<string> GetConsoleLines()
{
for (; ;)
yield return Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
这有两个问题:首先,Clone函数编写起来并不是特别简单(并且Reset没有意义).其次,序列是无限的 - 这是完全允许的.序列是懒惰的.
另一个例子:
IEnumerable<int> GetIntegers()
{
for (int n = 0; ; n++)
yield return n;
}
Run Code Online (Sandbox Code Playgroud)
对于这两个例子,你接受的"解决方法"没什么用处,因为它会耗尽可用内存或永远挂断.但这些都是完整有效的序列例子.
要了解C#和F#序列,您需要查看Haskell中的列表,而不是Scheme中的列表.
如果您认为无限的东西是红鲱鱼,那么从套接字读取字节怎么样:
IEnumerable<byte> GetSocketBytes(Socket s)
{
byte[] buffer = new bytes[100];
for (;;)
{
int r = s.Receive(buffer);
if (r == 0)
yield break;
for (int n = 0; n < r; n++)
yield return buffer[n];
}
}
Run Code Online (Sandbox Code Playgroud)
如果在套接字下发送了一些字节数,则不会是无限序列.然而,为它编写克隆将是非常困难的.编译器如何生成IEnumerable实现以自动执行?
一旦创建了克隆,两个实例现在都必须从他们共享的缓冲系统中工作.这是可能的,但实际上并不需要 - 这不是设计使用这些序列的方式.你纯粹在"功能上"对待它们,比如值,递归地应用过滤器,而不是"命令性地"记住序列中的位置.它比低级car/ cdr操纵更清洁.
进一步问题:
我想知道,我需要的最低级别的"原语"是什么,我可能想要在我的Scheme解释器中使用IEnumerable做任何事情都可以在方案中实现而不是作为内置实现.
我认为简短的回答是关注Abelson和Sussman,特别是关于溪流的部分.IEnumerable是一个流,而不是一个列表.它们描述了如何使用特殊版本的map,filter,accumulate等来处理它们.他们还在4.2节中提出了统一列表和流的想法.
| 归档时间: |
|
| 查看次数: |
5875 次 |
| 最近记录: |