我将会写一系列关于使用elm做游戏开发的文章,这是第一篇。这是一种即时编译成html和javascript的语言,因此你可以直接部署到web或在nw.js上将其打包,创建一个独立的app或者游戏。它没有太多的教程,但是很多东西我们必须学习我们才能进步。自从elm在开发圈子里活跃起来以后,为了防止文章过时,我将会一直更新文章,并且当存在任何错误时,我会改正。 函数式编程(FP)是一个让人摸不着头脑的典型范例。它的很多东西对很多人都是那样,但是它却代表了一群渴望写出更简单代码的人,他们避免强编织(complecting)并创建易于调试的软件。 |
Games
|
Iteration看看下面最简单的js例子,对于一个数组取平方。使用"命令式"的代码你会描述一些将要发生的事情。而用functional代码(声明式编程的子集),你去描述你想要做的事情。所以"命令式"的风格中我们会定义一个临时的index变量然后创建一个循环,遍历一遍数组,然后每个value取平方。
相比起来,functional的方法路线呢,如果你写js可以考虑下lodash这个库。然而使用一个专门是functional programming的语言,会比的很容易,所以我们使用elm来做这件事。
使用elm我们不需要定义临时变量,我们也会创建一个数组更容易,而且定义一个function复用。通过map我们将每个list的数字取平方,然后返回一个新的list。 正如你看到的,functions是对于传进来的每个变量有类型提示的。import List (..)这一行简单引入了核心list function,elm自带的这些function 提供了 map和filter的方法。 译者注: loadash的functional 路线
|
Filtering现在设想一下我们想从数组中移除奇数,然后只平方哪些过滤后的数组。通常,“命令式”的js是这样写的:
当然,这样写可以用,但是定义另外一个数组看起来很乱,而且我们还是得写循环。这就是"命令式"代码最不具有新意的地方。你可能会在你的代码的1000个地方重复写上面的代码。 现在我们试试functional 的写法:
我们在numbers里增加一个filter,然后这块方法就变得可以复用了,我们不需要对于有点不同的需求写重复代码。 这里就是functional programming闪耀的地方了,你花了更少的时间在编写想要的做的东西上,而且代码阅读起来也很方便。还有就是这证明了方法是可以链式调用的。 |
Chaining如果你现在觉得方法的nest调用会变得失控,你是对的。在elm语言中我们可以使用 |>操作符去帮助我们链式调用方法。 |> 操作符是 functional 程序的别名,它取得左边所有的参数然后传递this当作最后一个参数,this是最右边的参数。仍有<|是反向作用上述过程的。
当有多个function被调用,我们很容易看到这个的好处。
这样做减少了需要写的括号,而且使得代码更易读,变得更像一句话:
|
Composition
|
-- this (isEven >> not) -- is equivalent to (\n -> not (isEven n)) |
从逻辑上来考虑,如果我们知道 g : A -> B 和 f : B -> C(译者: 方法g是从状态A -> B, 方法f是状态B -> C),我们可以将f和g compose起来通过创建一个g >> f ,就是 A ->B ->C,(而且这个顺序可以是反向的 f << g : A -> C)。
在这个例子中中我们检测数字是否是奇数:
squareIsOdd = square >> isEven >> not -- `not` 是一个built- in 的方法用作布尔值反转 squareIsOdd 3 == True squareIsOdd 7 == False |
这个inputs给了squareIsOdd一个 composed的方法,每一个方法调用时都返回了一个结果,用作下一个方法的参数。
State
|
var foo, bar; foo = { "baz" : 1 "setBaz" : function (value) { this .baz = value; bar.qux = value * 2; // 讨厌! } }; bar = { "qux" : 2 }; foo.setBaz(2); |
可能有一些修改bar.qux的原因,比如bar.qux应当永远是foo.baz的两倍。但是直到开发者看了setBaz的源码之后他们才会知道bar.qux改变了。对象的api骗人了,这个例子是一个你可以明确的,容易的,识别出的糟糕代码。但是这样写"相当有效",所以不可避免的导致程序员这写。我自己看到过和这么写过太多太多这种代码。
所以,如何解决问题呢?不为开发者提供这些功能就行。elm没有全局变量,没有变量,只有input和output。
然而如果function没有任何update操作,仅仅只是返回了input,output和input是同一内容,这样避免了不必要的拷贝。
所以取setBaz这个例子:
我们看到setFooBaz是没有办法修改bar.quz的。这个方法是没有办法修改scope外面的值的,所以只能返回一个新的foo. 澄清一下,你可能这么想foo: Foo是一个type为 Foo的变量,但是它不是。它只是一个function不需要input然后output一个对象。我们可以很容易改变一个东西成Foo: Int -> Foo,去让baz被实例化成一种value。 如果我们仍想要确保bar.qux被及时更新成为foo.baz的两倍,我们可以创建一个方法,这个方法是被两个方法compose成的,被增加了2次人后返回原来的对象。
我们能够update这个值,向我们想的那样,但是没有副作用。update操作的output值包含了各种操作的影响。 Elm在我看来,functional语言有很多优势,通过上面的例子。阅读、debug、复用都很方便无副作用。所以为什么不去试着在写一个游戏呢。 |
本文转自:开源中国社区 [http://www.oschina.net]
本文标题:使用函数式编程语言 ELM 开发游戏
本文地址:http://www.oschina.net/translate/developing-games-in-elm
参与翻译:21paradox-, 无若, LeoXu
英文原文:Developing games in Elm Functional Programming