所以我之前已经阅读了很多次,技术上.NET 确实支持尾调用优化(TCO),因为它有操作码,只有C#不生成它.
我不确定为什么TCO需要操作码或它会做什么.据我所知,能够进行TCO的要求是递归调用的结果不与当前函数范围中的任何变量组合.如果你没有那个,那么我看不到操作码如何阻止你必须保持堆栈框架打开.如果你有,那么编译器是否总能轻易地将其编译为迭代的东西?
那么操作码有什么意义呢?显然有一些我不知道的东西.在完全可以使用TCO的情况下,不能总是在编译器级别处理,而不是在操作码级别处理?什么是不能的例子?
基于丰富的stackoverflow,我一直在研究是否对特定的c#代码进行了尾递归优化.一些问题似乎在讨论
从C#4.0(Visual Studio 2013/2015)开始,如果可以确保尾递归优化,如何确保尾递归优化呢?
我一直想在网上和这个网站上找几个小时回答这个问题的答案,我不在那里.
我知道.NET会为应用程序分配1MB,并且最好通过重新编码而不是强制堆栈大小来避免堆栈溢出.
我正在开发一个"最短路径"的应用程序,可以运行大约3000个节点,此时它会溢出.这是导致问题的方法:
public void findShortestPath(int current, int end, int currentCost)
{
if (!weight.ContainsKey(current))
{
weight.Add(current, currentCost);
}
Node currentNode = graph[current];
var sortedEdges = (from entry in currentNode.edges orderby entry.Value ascending select entry);
foreach (KeyValuePair<int, int> nextNode in sortedEdges)
{
if (!visited.ContainsKey(nextNode.Key) || !visited[nextNode.Key])
{
int nextNodeCost = currentCost + nextNode.Value;
if (!weight.ContainsKey(nextNode.Key))
{
weight.Add(nextNode.Key, nextNodeCost);
}
else if (weight[nextNode.Key] > nextNodeCost)
{
weight[nextNode.Key] = nextNodeCost;
}
}
}
visited.Add(current, true);
foreach (KeyValuePair<int, int> nextNode in sortedEdges)
{
if(!visited.ContainsKey(nextNode.Key) …Run Code Online (Sandbox Code Playgroud) 我有两个问题,源于观察到的C#静态方法的行为(我可能会误解):
第一:递归静态方法在某种意义上是通过静态方法在封面下实现的方式进行尾调用优化吗?
第二:使用静态方法编写整个应用程序并且没有超出局部范围的变量,它是否等同于函数式编程?我很想知道,因为我仍然没有把这个"没有副作用"的术语包围起来,我一直听说功能性编程.
编辑:让我提一下,我确实使用并理解为什么以及何时在正常的C#OO方法中使用静态方法,并且我确实理解尾部调用优化不会明确地对递归静态方法进行.也就是说,我理解尾部调用优化是尝试在每次传递时停止创建新的堆栈帧,并且我在几个点观察到在它的调用方法的框架内执行的似乎是一个静态方法,尽管我可能误解了我的观察.
我使用CSharpCodeProvider编译我的代码,并在结果汇编中动态创建某个类的实例.比我叫一些方法.如果方法有递归,我得到StackOverflowException,我的应用程序终止.
我该如何避免这种情况?
using System;
using System.Runtime.Remoting;
namespace TestStackOverflow
{
class Program
{
class StackOver : MarshalByRefObject
{
public void Run()
{
Run();
}
}
static void Main(string[] args)
{
AppDomain domain = AppDomain.CreateDomain("new");
ObjectHandle handle = domain.CreateInstance(typeof (StackOver).Assembly.FullName, typeof (StackOver).FullName);
if (handle != null)
{
StackOver stack = (StackOver) handle.Unwrap();
stack.Run();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我试图从f#调用这个函数
功能签名是:
CloudStorageAccount.SetConfigurationSettingPublisher
(Action<string, Func<string, bool>>) : unit
Run Code Online (Sandbox Code Playgroud)
C#调用是这样的:
CloudStorageAccount.SetConfigurationSettingPublisher((configName,
configSettingPublisher) =>
{
string configValue = "something"
configSettingPublisher(configValue);
});
Run Code Online (Sandbox Code Playgroud)
而在F#中,我必须做这样的事情:
let myPublisher configName (setter:Func<string, bool>) =
let configValue = RoleEnvironment.GetConfigurationSettingValue(configName)
setter.Invoke(configName) |> ignore
let act = new Action<string, Func<string, bool>>(myPublisher)
CloudStorageAccount.SetConfigurationSettingPublisher(act)
Run Code Online (Sandbox Code Playgroud)
这可以在f#中更简洁地写出来吗?
我有一个包含的嵌套列表
public class Person
{
public Person(string name)
{
this.Name = name;
}
public string Name { get; set; }
public List<Person> Childs { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
该列表可以像这样使用:
var Persons = new List<Person>();
Persons.Add(new Person("Eric"));
Persons[0].Childs = new List<Person>();
Persons[0].Childs.Add(new Person("Tom"));
Persons[0].Childs.Add(new Person("John"));
Persons[0].Childs[0].Childs = new List<Person>();
Persons[0].Childs[0].Childs.Add(new Person("Bill"));
Persons.Add(new Person("John");
Run Code Online (Sandbox Code Playgroud)
如何展平这棵树(将所有节点和子节点以及子子节点放入列表中),例如,我想在同一级别上使用“参数”级别显示所有子级和父级。这意味着:
之前:
-Eric
-Tom
-John
-Bill
Run Code Online (Sandbox Code Playgroud)
我想要的是:
-Eric, Level1
-Tom, Level2
-John, Level2
-Bill, Level3
Run Code Online (Sandbox Code Playgroud) 作为进入合并排序的第一次尝试,我生成了以下代码,这些代码适用于字符串,因为它们比列表更容易处理.
class Program
{
static int iterations = 0;
static void Main(string[] args)
{
string test = "zvutsrqponmlihgfedcba";
test = MergeSort(test);
// test is sorted after 41 iterations
}
static string MergeSort(string input)
{
iterations++;
if (input.Length < 2)
return input;
int pivot = 0;
foreach (char c in input)
pivot += c;
pivot /= input.Length;
string left = "";
string right = "";
foreach (char c in input)
if (c <= (char)pivot)
left += c;
else
right += c; …Run Code Online (Sandbox Code Playgroud) 我试图使用递归从数组返回最大元素
这里是我的代码
static void Main(string[] args)
{
int[] Array=new int[]{10,233,34};
int _MaxVal = CalculateMax(Array, 0, 0);
Console.WriteLine(_MaxVal);
Console.ReadKey();
}
private static int CalculateMax(int[] Array, int Startpos, int maxval)
{
if (Startpos != Array.Length)
{
if (Array[Startpos] > maxval)
{
maxval = Array[Startpos];
}
CalculateMax(Array, ++Startpos, maxval);
}
return maxval;
}
Run Code Online (Sandbox Code Playgroud)
我得到MaxVal为10.
这有什么问题?
谢谢大家
编辑:显然偏离主题...转移到Programmers.StackExchange.com.
这不是一个实际问题,它更像是一个谜.
我很想知道是否有办法实现与以下相同的东西,但不使用yield:
IEnumerable<T> Infinite<T>()
{
while (true) { yield return default(T); }
}
Run Code Online (Sandbox Code Playgroud)
yield关键字mscorlib.dll,System.Core.dll?不确定还包括哪些内容).但是,如果您找到一些其他.NET程序集(WPF ?!)的解决方案,我也很感兴趣.我最接近的是:
IEnumerable<int> infinite = null;
infinite = new int[1].SelectMany(x => new int[1].Concat(infinite));
Run Code Online (Sandbox Code Playgroud)
这是"正确的",但在14399次迭代通过可枚举(非常无限)之后会遇到StackOverflowException.
我认为由于CLR 缺乏尾递归优化,可能无法做到这一点.证明会很好:)