erlang's list

[size=large]在看《programming erlang》的时候,一直对list的操作有疑问,比如说java会有很多的东西,比方说append,add,delete,sort,get,等等,会有很多,而这里,只有两个小节。真的很精简。
由于不存在更改的问题,事情变得简单多了。

首先,你要有,也就是创建。
L=[1,2,3,4,5,6]
ok,我们有了。
那我们要加入或者删除呢?
这里分了方向了,加入和删除是不同的概念,但是都是更改,所以,你要有另建两个变量的准备。
而这两个动作虽然性质相同,但是在操作方式上很不同,结果当然是相反。
加入:L1=[9|L] 行了!那我要是加入多个呢?L2=[9,8|L],随便,前面加几个都行。

而删除则刚好用到了erlang的另一个基本概念,或者说基石,模式匹配。
何为模式匹配?基本上是分解,比如说你吃一只鸡,你要鸡腿还是翅膀呢?我要的是一块,东西要一口一口的吃嘛!
由于erlang的数据是只能建,不能改,所以你只要建立一个被分解了的数据,也就是删除了。当然,你要留下你要的那块肉!
所以,[My9|Other]=L1,L1第一个是9,现在,我就要9。Other就成了L。当然了,我说的是数据,内容相同。现在从Other的角度上讲,就等于删除了9;从My9的角度讲,就等于删除了与L相同的所有数据。
同样,如果你要分离出多个,[My9,My8|Other]=L2。这样就提出了9,8,和剩下的Other还是和L相同内容。

所以,基本的东西就是这两方面。一个是创建,一个是提取。
而提取也是一种创建,只不过创建的是更小片的而已。
总之,你所有拿到的不同的东西都是新的,另外创建的。
所以,模式匹配也可以说是另一种方式的创建。

之所以会这样,这和函数是编程的变量不变性是紧密相关的,从这个方向考虑,这一切也就自然而然了。
只是,我还不太习惯[A|L]之类的结构,因为java用的都太木了。
:arrow: :arrow: :arrow: :arrow: :arrow: :arrow: :arrow: :arrow: :arrow:
周末,下了7盘棋,5胜2负。
成绩还不错吧?不过有一盘是对方掉线了,胜的。还有一盘是对方读秒阶段超时负,而那盘我形势大差,算是捡了一盘。最后一盘颇为艰苦,下了接近300手,最后我半目胜。真的要崩溃了。
我发现我的棋风应该属于平衡加力战型的。通常都是我挑起战斗,有时候,我甚至不能控制的四处断,杀,想得到把对方杀崩,渴望那种爆裂的快感。
:arrow: :arrow: :arrow: :arrow: :arrow: :arrow: :arrow: :arrow: :arrow:
写完以上内容,我会去想了想,如果我们想在列表的尾部加一个元素呢?
于是,我写了个小程序演习了一下:
[/size]

-module(myappend).
-compile(export_all).
%% 在这里,我用的全都是最基本的操作,而把这些基本动作连接起来的就是函数的递归调用。
%% 在参数里,我的结果一步一步的接近完整,直到最后返回。
%% 这好像是最基本的手法,如何强调都不过分的那种。
append(L,T) -> append_list(reverse(L),[T]).
append_list([H|T],L) -> append_list(T,[H|L]);
append_list([],L) -> L.

reverse(L) ->reverse(L,[]).
reverse([H|T],L) -> reverse(T,[H|L]);
reverse([],L) -> L.
%% 一共就6行,而且中间没有任何烂七八糟的语句,这的确有点意思。
%% 而且,发现没?后两个append_list和后两个reverse的处理基本是一样的,好像可以再精简一下。
%% 成这样,如下:
-module(myappend).
-compile(export_all).
append(L,T) -> moveto(reverse(L),[T]).
reverse(L) ->moveto(L,[]).
%% 这段的逻辑应该是从一个列表转移到另一个列表,当然,顺序相反。
moveto([H|T],L) -> moveto(T,[H|L]);
moveto([],L) -> L.
%% 这样就变成4行了。

[size=large]
既然是从尾部加,那么就让你要加的东西变成一个列表,然后再从头部,一个一个的加。
但是问题是那样的话,顺序反了,所以,要再写个反转的函数,给它掉个个。
我想可能得有好几种处理方法,这样效率是不是会低呢?不晓得。
写函数时,对于空表和非空表处理的常见性,让我有点吃惊。
这种[H|T]和[]的区别,erlang是能自己分清的——我本来以为只要是有两个参数的,不管什么类型它都分不清呢!

函数式编程的时候,状态是在参数里维护的,因为你不可能建太多的变量(当然它是不变的),比如说在遍历列表的时候,所以,只要你想变的时候,就调函数就好了,让函数来维护一个一致的状态。不管你调用函数多少次,都不会浪费资源,因为那是应该的。你的变化的状态在函数的参数之间传递和改变,你只要在适当的时候,返回变化好了的参数就可以了。
这算我的一点点体会吧!
[/size]
:arrow: :arrow: :arrow: :arrow: :arrow: :arrow: :arrow: :arrow: :arrow:
[size=large]
写了上述东西之后,觉得有些意犹未尽,看了看getting started,发现我的写法没问题,是标准写法,效率也没问题。
那个list_max的例子引起了我的注意:
[/size]

list_max([Head|Rest]) -> list_max(Rest,Head).
list_max([],Res) -> Res;
list_max([Head|Rest],Result_so_far) when Head > Result_so_far -> list_max(Rest,Head);
list_max([Head|Rest],Result_so_far) -> list_max(Rest,Result_so_far).

[size=large]
差别是那个when,它替代了if,使得风格变得漂亮。
这种东西文档里说是guard,而中文翻译成了断言,很不恰当。
这种函数入口的选择,看似微小,实则非常的重要。
它弥补了动态语言的弱点,使得可以根据某些特性来选择进那个函数。
如果用if写的话,是这样:
[/size]

list_max([Head|Rest]) -> list_max(Rest,Head).
list_max([],Res) -> Res;
list_max([Head|Rest],Result_so_far) ->
if
Head > Result_so_far -> list_max(Rest,Head);
Head =< Result_so_far -> list_max(Rest,Result_so_far)
end.

[size=large]
搞笑的是,那个Head =< Result_so_far,我开始写成<=,结果怎么也不对,我查了下才清楚,它居然写成那样!
[/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值