我编写了一个很小的递归F#代码来查看我可以在.NET/Mono下的堆栈中放入多少级别的递归.它只是在精确的2次幂时打印递归深度,所以我发现最大深度在2的范围内.
我在一个具有定义的堆栈空间量的线程中启动代码System.Threading.Thread (ThreadStart, int).在.Net下,每个递归级别似乎需要大约100个字节,而我可以在2G堆栈上获得大约1600万个级别.Mono下的内存使用情况大致相似,但是我只能获得大约3万个级别.增加传递给Thread过去的堆栈大小值600000不会增加递归深度.
ulimit 报告堆栈大小限制为1G.
一个明显的解释是Mono不会服从第二个论点,Thread如果它太大了.有没有人知道如何说服Mono分配一个大堆栈?
代码是微不足道的,但它只是在某些人关心的情况下:
let rec f i =
if popcount i = 1 then // population count is one on exact powers of 2
printf "Got up to %d\n" i
stdout.Flush ()
if i = 1000000000 then 0 else 1 + f (i+1)
Run Code Online (Sandbox Code Playgroud) 我在F#中有一些代码在.net下工作正常但在Mono下溢出了堆栈.一个相关的问题是它似乎早在可能可用的堆栈空间耗尽之前就已经用完了(它以System.Threading.Thread(ts,1000000000)开头).据我所知,它死的折叠是尾递归的,堆栈跟踪看起来好像没有进行尾部优化.我用--optimize = tailc运行3.2.1.
有人请确切知道什么样的尾调用删除调用堆栈,哪些不?或者如何分配更多堆栈?非常感谢.
我知道Mono中的Tailcall消除
编辑:这是评论中要求的代码大纲.它是大型数据结构折叠的一部分,但失败的堆栈跟踪只有mapk和myfold.
let rec myfold f x k =
let rec mapk xs k =
match xs with
[] -> k []
| x::xs -> mapk xs (fun xs' -> myfold f x (fun x' -> (x' :: xs') |> k))
...
mapk (...) ( ... >> k)
Run Code Online (Sandbox Code Playgroud) 以下是一些不会因复杂性而获奖的代码:
[<EntryPoint>]
let main argv =
let i = 1I
printfn "One is %A\n" i
0 // return an integer exit code
Run Code Online (Sandbox Code Playgroud)
它的编译如下:"c:/ Program Files(x86)/ Microsoft SDKs/F#/ 3.0/Framework/v4.0/Fsc.exe"--out:numericstest.exe --debug:full --target:exe - - standalone Program.fs
在Windows下,它会产生预期的结果.但是根据在Ubuntu下编译的Mono 3.0.7,它反而说:
mono numericstest.exe
Unhandled Exception: System.InvalidProgramException: Invalid IL code in System.Numerics.BigInteger:get_One (): method body is empty.
at Program.main (System.String[] argv) [0x00000] in <filename unknown>:0[ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidProgramException: Invalid IL code in System.Numerics.BigInteger:get_One (): method body is empty.
at Program.main (System.String[] argv) [0x00000] in <filename …Run Code Online (Sandbox Code Playgroud) 编辑:从目前为止添加的答案和评论看来,我没有正确解释我想要的内容.这是一个例子:
// type not supporting any type of comparison
[<NoEquality>]
[<NoComparison>]
type blah () =
member x.huha = 0
// make a map, turns out to work whether x supports equality or not
let inline tt x =
Map.ofList [1, x]
let test () =
// maps can be compared for equality if the argument can
if (tt 1 = tt 2) then failwithf "strange"
// maps can be made no matter if the argument supports equality
if (tt (blah …Run Code Online (Sandbox Code Playgroud) 看看各种文档,在F#中定义事件的方法就是做类似的事情
type xyz () =
let e = new Event<T>
member x.something_happened : IEvent<T> = x.Publish
Run Code Online (Sandbox Code Playgroud)
不幸的是,IEvent的类型实际上是Miscrosoft.FSharp.Control.IEvent <_>,因此很难在C#中使用.有些文章建议将CLIEvent属性添加到上面的成员something_happended中,但就C#的可用性而言,它似乎没有任何区别,而不包括F#库.
如何在F#中正确定义事件,以便我可以在C#代码中添加一个委托?非常感谢.