我最近发现了一个关于适合 Python 程序员的 F# http://combiol.org/fs/FSUG_FS4PPv2.pptx,看完之后,我决定自己实现一个“蚂蚁谜题”的解决方案。
有一只蚂蚁可以在平面网格上走动。蚂蚁一次可以向左、向右、向上或向下移动一格。也就是说,蚂蚁可以从单元格 (x, y) 前往单元格 (x+1, y)、(x-1, y)、(x, y+1) 和 (x, y-1)。 x 和 y 坐标的数字之和大于 25 的点是蚂蚁无法到达的。例如,点(59,79)是不可访问的,因为5 + 9 + 7 + 9 = 30,大于25。问题是:如果从(1000, 1000)开始,蚂蚁可以访问多少个点,包括 (1000, 1000) 本身?
我用 30 行代码实现了我的解决方案首先是 OCaml http://pastebin.com/EzMt466b,并尝试了一下:
$ ocamlopt -unsafe -rectypes -inline 1000 -o puzzle ant.ml
$ time ./puzzle
Points: 148848
real 0m0.143s
user 0m0.127s
sys 0m0.013s
好吧,我的结果和leonardo 的 D 和 C++ 实现 http://leonardo-m.livejournal.com/。与 Leonardo 的 C++ 实现相比,OCaml 版本的运行速度大约比 C++ 慢 2 倍。鉴于 Leonardo 使用队列来删除递归,这没关系。
I then 将代码翻译为 F# http://pastebin.com/0Vx5GTBQ...这就是我得到的:
Thanassis@HOME /g/Tmp/ant.fsharp
$ /g/Program\ Files/FSharp-2.0.0.0/bin/fsc.exe ant.fs
Microsoft (R) F# 2.0 Compiler build 2.0.0.0
Copyright (c) Microsoft Corporation. All Rights Reserved.
Thanassis@HOME /g/Tmp/ant.fsharp
$ ./ant.exe
Process is terminated due to StackOverflowException.
Quit
Thanassis@HOME /g/Tmp/ant.fsharp
$ /g/Program\ Files/Microsoft\ F#/v4.0/Fsc.exe ant.fs
Microsoft (R) F# 2.0 Compiler build 4.0.30319.1
Copyright (c) Microsoft Corporation. All Rights Reserved.
Thanassis@HOME /g/Tmp/ant.fsharp
$ ./ant.exe
Process is terminated due to StackOverflowException
堆栈溢出...我的机器上有两个版本的 F#...
出于好奇,我然后获取生成的二进制文件(ant.exe)并在 Arch Linux/Mono 下运行它:
$ mono -V | head -1
Mono JIT compiler version 2.10.5 (tarball Fri Sep 9 06:34:36 UTC 2011)
$ time mono ./ant.exe
Points: 148848
real 1m24.298s
user 0m0.567s
sys 0m0.027s
令人惊讶的是,它在 Mono 2.10.5 下运行(即没有堆栈溢出) - 但需要 84 秒,即比 OCaml 慢 587 倍 - 哎呀。
所以这个程序...
- 在 OCaml 下运行良好
- 在 .NET/F# 下根本不起作用
- 在 Mono/F# 下可以工作,但速度非常慢。
Why?
EDIT:怪异仍在继续 - 使用“--optimize+ --checked-”使问题消失,但仅限于 ArchLinux/Mono 下;在Windows XP和Windows 7/64位下,即使是优化版本的二进制堆栈也会溢出。
最终编辑:我自己找到了答案 - 见下文。