功能语言是飞行模拟器的好选择吗? Lisp怎么样?

时间:2009-04-05 13:31:05

标签: functional-programming lisp simulation

我已经做了几年的面向对象编程,而且我没有做太多的函数式编程。我对飞行模拟器感兴趣,并对Lisp的函数编程方面感到好奇。飞行模拟器或任何其他真实世界的模拟器在面向对象的范例中对我有意义。

以下是我的问题:

面向对象是表示真实世界模拟域的最佳方式吗?

我知道Common Lisp有CLOS(针对lisp的OO),但我的问题是关于用函数式语言编写飞行模拟器。所以如果你打算用Lisp编写它,你会选择使用CLOS还是以函数方式编写它?

有没有人对使用lisp或任何功能语言编写飞行模拟器进行编码有什么想法?

更新11/8/12 - 对于那些感兴趣的人来说类似的问题 - > How does functional programming apply to simulations?

7 个答案:

答案 0 :(得分:12)

将“Lisp”视为一种功能语言是一个常见的错误。真的,它最好被认为是一个语言家族,但是现在人们说Lisp它们通常意味着Common Lisp。

Common Lisp允许函数式编程,但它本身不是函数式语言。相反,它是一种通用语言。 Scheme是一个小得多的变体,在方向上更具功能性,当然也有其他变体。

至于你的问题,这是一个不错的选择吗?这真的取决于你的计划。 Common Lisp尤其对这类事情有一些真正的优势。它在您通常在所谓的脚本语言中看到的级别上具有交互性和内省性,使得开发速度非常快。同时编译并具有高效的编译器,因此您可以期望与其他高效编译器在同一个球场中的性能(c的两倍是典型的ime)。虽然它是一种大型语言,但它具有比c ++更加一致的设计,并且元编程功能可以为您的特定应用程序创建非常干净,易于理解的代码。如果你只看这些方面 常见的lisp看起来很神奇。

然而,还有缺点。社区很小,如果你正在寻找的话,你找不到很多人可以帮忙。虽然内置库很大,但您找不到尽可能多的第三方库,因此您最终可能会从头开始编写更多内容。最后,虽然它绝不是一个有围墙的花园,但CL并没有像python那样与外国图书馆的顺利整合。这并不意味着你不能调用c代码,有很好的工具。

按照他们的方式,CLOS是我能想到的最强大的OO系统,但如果你来自主流的c ++ / java / c#/等,这是一个完全不同的方法。 OO背景(是的,它们有所不同,但超出了单个与多个inh。并没有那么多)你可能会发现它起初有点奇怪,几乎完全由内而外。

如果你走这条路线,如果用CLOS自己编写,那么你将不得不注意实际渲染管道性能的一些问题。类系统具有令人难以置信的运行时灵活性(即在运行时更新类定义,而不是通过猴子修补等,但通过实际更改类和更新实例),但是您需要为此支付一些调度成本。

对于它的价值,我过去曾使用过CL作为需要数值效率的研究代码,即不同类型的模拟。这对我来说很有用。在那种情况下,我并不担心使用现有的代码 - 它不存在,所以无论如何我都是从头开始写几乎所有的东西。

总之,它可能是这个项目的一个很好的语言选择,但不是唯一的。如果你不使用具有高级方面和良好性能的语言(如CL,OCaml和其他一些语言),我肯定会看到使用像lua这样的语言进行两级方法的可能性python(很多libs)在一些c或c ++代码之上执行繁重的工作。

答案 1 :(得分:8)

如果你看一下游戏或模拟器行业,你会发现很多 C ++ 以及一些添加的脚本组件。还可以使用其他语言编写用于风景设计或相关任务的工具。但是在该领域中只使用了很少的Lisp。您需要成为一名优秀的黑客才能从Lisp中获得必要的性能,并能够访问或编写低级代码。你怎么知道这个?尝试,失败,学习,尝试,失败少,学习,......只有编写代码并尝试使用它。 Lisp对于优秀的软件工程师或那些有可能成为优秀软件工程师的人来说非常有用。

主要障碍之一是垃圾收集器。要么你有一个非常简单的(然后你有随机暂停的性能问题)或你有一个复杂的(然后你有一个问题,让它正常工作)。只有少数垃圾收集器是合适的 - 大多数Lisp实现具有良好的GC实现,但仍然没有针对实时或接近实时的使用进行调整。确实存在例外情况。使用C ++,您可以忘记GC,因为通常没有。

使用垃圾收集器进行自动内存管理的另一种方法是不使用GC并“手动”管理内存。一些(甚至是商业的)Lisp应用程序使用它来支持某些实时响应(例如过程控制专家系统)。

在该领域开发的最近的东西是来自Naughty Dog的Playstation I(后来的游戏是Playstation II)的 Crash Bandicoot (以及后来的游戏)游戏。由于他们已经被索尼收购,他们为Playstation III换成了C ++。他们的开发环境是用Allegro Common Lisp编写的,它包含一个Scheme(一个Lisp方言)变体的编译器。在开发系统上,代码被编译,然后在开发期间下载到Playstation。他们有自己的3D引擎(非常令人印象深刻,总是得到游戏杂志的优秀评论),增量级别加载,许多不同演员的复杂行为控制等等。所以Playstation真的执行了Scheme代码,但内存管理没有完成通过GC(afaik)。他们必须自己开发所有技术 - 没有人提供基于Lisp的工具 - 但他们可以,因为他们是优秀的软件开发人员。从那时起,我还没有听说过类似的项目。请注意,这不仅仅是用于编写脚本的Lisp - 它一直是Lisp。

Scheme方面还有一个名为Ypsilon Scheme的新兴趣实现。它是为弹球游戏开发的 - 这也可能是其他游戏的基础。

在Common Lisp方面,有一些Lisp应用程序与飞行模拟器交谈并控制它们的各个方面。有些游戏库基于SDL。有OpenGL的接口。还有类似“开放代理引擎”的东西。还有一些用Common Lisp编写的3d图形应用程序 - 甚至是一些复杂的应用程序。但是在飞行模拟领域,现有技术很少。

关于CLOS与功能编程的主题。可能人们都不会使用。如果您需要从系统中挤出所有可能的性能,那么CLOS已经有一些人们可能想要避免的开销。

答案 2 :(得分:6)

看看Functional Reactive Programming。在Haskell中有许多这样的框架(不了解其他语言),其中大多数是基于箭头的。基本思想是表示时变值和事件之间的关系。因此,例如,您将编写(使用没有特定库的Haskell箭头符号):

   velocity <- {some expression of airspeed, heading, gravity etc.}
   position <- integrate <- velocity

第二行声明了位置和速度之间的关系。 &lt; - 箭头操作符是一堆将所有内容组合在一起的库调用的语法糖。

然后你可能会说:

   groundLevel <- getGroundLevel <- position
   altitude <- getAltitude <- position
   crashed <- liftA2 (<) altitude groundLevel

声明如果你的海拔高度低于你所在位置的地面,那么你就已经崩溃了。就像这里的其他变量一样,“崩溃”不仅仅是一个单一的值,它是一个随时间变化的值流。这就是“liftA2”功能用于将比较运算符从简单值“提升”到流的原因。

IO在这个范例中不是问题。输入是时变值,例如操纵杆X和Y,而屏幕上的图像只是另一个时变值。在最顶层,您的整个模拟器是从输入到输出的箭头。然后你调用一个“运行”功能,将箭头转换为运行游戏的IO动作。

如果你用Lisp写这个,你可能会发现自己创建了一堆基本上重新发明箭头的宏,所以最好先找出箭头。

答案 3 :(得分:2)

我对飞行模拟游戏一无所知,你没有列出任何具体的内容,所以这主要是关于在Lisp中编写FS的猜测。

为什么不:

  • Lisp擅长探索性编程。我认为既然FS已经存在了很长时间,并且有免费的开源示例,那么这种类型的编程就不会受益匪浅。

  • 飞行模拟游戏大多是(我猜)用静态的本机编译语言编写的。如果您正在寻找纯运行时性能,那么在Lisp中,这往往意味着类型声明和其他不那么Lispy结构。如果你没有用天真的方法获得你想要的性能,那么你的优化-Lisp最终可能看起来很像C,而且在编写C时Lisp并不像C那样好。

  • 我猜测,很多FS正在连接到像OpenGL这样用C语言编写的图形库。根据你的FFI / OpenGL绑定方式,这可能会再次使你的代码看起来像C-in-Lisp。你可能没有Lisp所做的大赢,例如,一个Web应用程序(它包含生成纯文本的树结构,Lisp很擅长)。

为什么:

  • 我瞥了一眼FlightGear的源代码,我看到了很多结构样板 - 即使是一个直的端口也可能只有一半的尺寸。

  • 他们在整个地方都使用字符串(C ++没有符号)。他们将XML用于半人类可读的配置文件(C ++没有运行时阅读器)。只需在这里切换到本机Lisp构造就可以获得最小的努力。

  • 没有任何东西看起来很复杂,甚至是“AI”。这只是让所有事情都井然有序的问题,Lisp会很擅长这一点,因为它会缩短很多。

但Lisp的巧妙之处在于它是多范式的。您可以使用OO来组织“对象”,并使用FP在每个对象中进行计算。我说只是开始写作,看看你需要的地方。

答案 4 :(得分:1)

我不会说功能编程特别适合飞行模拟。通常,函数语言可以对于编写科学模拟非常有用,尽管这是一个稍微专业化的案例。真的,你可能会更好地使用标准的命令式(最好是OOP)语言,比如C ++ / C#/ Java,因为它们往往会有更好的物理库和图形API,你需要使用它们。巨资。此外,OOP方法可以更容易地表示您的环境。另一点需要考虑的是(据我所知)当今市场上流行的飞行模拟器完全用C ++编写。

基本上,我的理念是,如果你没有特别好的理由需要使用功能范例,那么就不要使用函数式语言(尽管没有什么可以阻止你在OOP /混合语言中使用函数结构)。我怀疑使用经过充分测试的C ++ API以及与游戏开发相关的语言(与飞行模拟游戏有很多共同点)的开发过程会让您痛苦不堪。现在,如果你想在模拟器中添加一些复杂的AI,Lisp可能看起来是一个相当明显的选择,尽管如此,我根本不会跳过它。最后,如果你真的热衷于使用函数式语言,我建议你选择一个更通用的函数,比如Python甚至F#(两者都是混合命令函数语言),而不是Lisp,它可以最终对这样一个项目变得相当丑陋。

答案 5 :(得分:1)

我首先想到模拟的本质。

某些模拟需要像飞行模拟器那样进行交互。我不认为函数式编程可能是交互式(读取:CPU密集型/响应关键型)应用程序的不错选择。当然,如果你可以访问8个与Linux连接的PS3,你就不会太在意性能。

对于像进化/遗传编程这样的模拟,你设置它并让它们扯掉,一个功能上的语言可能比OO语言更有助于建立问题域的模型。并不是说我是函数式编程方面的专家,但编码递归的简易性和函数式语言中常见的懒惰评估的概念在我看来非常适合“让她扯掉”类型的sims。

答案 6 :(得分:0)

函数式语言存在一些问题,即它们与状态不匹配,但它们与进程相关。所以在某种程度上可以说它们是行动导向的。这意味着你将浪费时间模拟飞机,你想要做的是模拟飞机飞行的动作。一旦你感到严峻,你就可以让它发挥作用。

现在作为侧点,haskell不会是好的恕我直言,因为它对于“游戏”来说太抽象了,这种应用程序都是关于输入/输出,但Haskell是关于避免IO,所以它将成为一个monad噩梦,你会反对这种语言。 Lisp是一个更好的选择,或Lua或Javascript,它们也是功能性的,但不是纯粹的功能,所以对于你的情况尝试Lisp。无论如何,在任何一种语言中,您的图形都将是C或C ++。

然而,一个严重的问题是文档很少,关于功能语言和“游戏”的教程较少,当然科学模拟在学术上是有记录的,但那些论文非常密集,如果你成功,也许你可以写下你的经验,其他人,因为它现在是一个相当空的领域