我白天是一名.NET开发人员,但现在我在业余时间和Haskell玩了一段时间.我很好奇:任何Haskell .net实现与IronPython一样吗?
注意:我可能在标题中选择了错误的单词; 也许我真的在谈论多项式增长.请参阅此问题末尾的基准测试结果.
让我们从这三个表示不可变堆栈的递归通用接口†开始:
interface IStack<T>
{
INonEmptyStack<T, IStack<T>> Push(T x);
}
interface IEmptyStack<T> : IStack<T>
{
new INonEmptyStack<T, IEmptyStack<T>> Push(T x);
}
interface INonEmptyStack<T, out TStackBeneath> : IStack<T>
where TStackBeneath : IStack<T>
{
T Top { get; }
TStackBeneath Pop();
new INonEmptyStack<T, INonEmptyStack<T, TStackBeneath>> Push(T x);
}
Run Code Online (Sandbox Code Playgroud)
我创建了简单的实现EmptyStack<T>,NonEmptyStack<T,TStackBeneath>.
更新#1:请参阅下面的代码.
我注意到有关其运行时性能的以下内容:
EmptyStack<int>第一次将1,000件物品推到a上需要7秒多.EmptyStack<int>几乎没有时间.更新#2:
我终于进行了更精确的测量.请参阅下面的基准代码和结果.
我在这些测试中只发现.NET 3.5似乎不允许递归深度≥100的泛型类型..NET 4似乎没有这个限制.
前两个事实让我怀疑性能缓慢不是由于我的实现,而是由于类型系统:.NET必须实例化1,000个不同的封闭泛型类型,即:
EmptyStack<int>NonEmptyStack<int, EmptyStack<int>>NonEmptyStack<int, NonEmptyStack<int, EmptyStack<int>>> …我熟悉C#规范,第5.3节,它说在使用之前必须分配一个变量.
在C和非托管C++中,这是有道理的,因为堆栈没有被清除,并且用于指针的内存位置可能在任何地方(导致难以追踪错误).
但我的印象是运行时不允许真正的"未分配"值.特别是未初始化的引用类型将始终具有空值,而不是先前调用方法或随机值所遗留的值.
这是正确的,还是我错误地假设这些年来检查null是否足够?你可以在C#中使用非真实的变量,或者CLR是否会处理这个变量并且总是设置了一些值.
我有一个(C#)函数类似于以下.
private static bool SpecialCase = false;
public void Foo()
{
if (SpecialCase)
{
InternalMethod();
return;
}
Console.WriteLine();
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void InternalMethod();
Run Code Online (Sandbox Code Playgroud)
当我在调试器内部使用.NET Framework 4执行此操作时,该方法成功地将空白行打印到控制台并返回.当我在调试器外部执行它时,它会抛出一个带有以下消息的异常:
System.Security.SecurityException: ECall methods must be packaged into a system module.
Run Code Online (Sandbox Code Playgroud)
当JIT编译器编译方法而不是InternalMethod调用when(if)时,似乎抛出了异常.有什么我可以做的(例如属性)告诉CLI要么不抛出SecurityException,要么延迟异常直到实际调用该方法?
关于用例的附注:SpecialCase使用Microsoft .NET Framework运行时,该字段实际上是错误的,而在CLI的不同(特定)实现下运行时,该字段为true.在Microsoft .NET Framework下运行时,调用InternalMethod实际上无法访问.
假设我有这样的界面和具体实现
public interface IMyInterface<T>
{
T My();
}
public class MyConcrete : IMyInterface<string>
{
public string My()
{
return string.Empty;
}
}
Run Code Online (Sandbox Code Playgroud)
所以我创建了MyConcrete实现strings,我可以有一个更具体的实现int.那没关系.但是,让我们说,我想做同样的事情,但使用通用方法,所以我有
public interface IMyInterface2
{
T My<T>();
}
public class MyConcrete2 : IMyInterface2
{
public string My<string>()
{
throw new NotImplementedException();
}
}
Run Code Online (Sandbox Code Playgroud)
所以我有相同的IMyInterface2,但它通过定义通用行为T My<T>().在我的具体类中,我想实现My行为,但对于具体的数据类型 - string.但C#不允许我这样做.
我的问题是为什么我不能这样做?换句话说,如果我可以创建MyInterface<T>as的具体实现MyClass : MyInterface<string>并在此时停止泛化,为什么我不能用泛型方法做到这一点 - T My<T>()?
我一直在尝试这几种不同的方式,但我得出的结论是它无法完成.这是我过去从其他语言中享受的语言功能.这只是我应该注销的东西吗?
为什么.NET中的值为null?这是否优于保证所有内容都具有值并且没有任何调用为空?
任何人都知道这些方法的名称是什么?
无论哪种方式,我对此都知之甚少,但是在简单性方面,即在消除空检查方面,并且能够编写更加简化的算法而不必分支出来检查.
在性能,简洁性,平行性,面向未来等方面,每种风格的优缺点是什么?
stringbuilder.cs的Reference Source页面在ToString方法中有以下注释 :
if (chunk.m_ChunkLength > 0)
{
// Copy these into local variables so that they
// are stable even in the presence of ----s (hackers might do this)
char[] sourceArray = chunk.m_ChunkChars;
int chunkOffset = chunk.m_ChunkOffset;
int chunkLength = chunk.m_ChunkLength;
Run Code Online (Sandbox Code Playgroud)
这是什么意思?被----s一些恶意用户可能会插入一个字符串格式化?
clr ×10
.net ×8
c# ×7
performance ×2
generics ×1
haskell ×1
recursion ×1
type-systems ×1
types ×1