在看《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用的都太木了。
周末,下了7盘棋,5胜2负。
成绩还不错吧?不过有一盘是对方掉线了,胜的。还有一盘是对方读秒阶段超时负,而那盘我形势大差,算是捡了一盘。最后一盘颇为艰苦,下了接近300手,最后我半目胜。真的要崩溃了。
我发现我的棋风应该属于平衡加力战型的。通常都是我挑起战斗,有时候,我甚至不能控制的四处断,杀,想得到把对方杀崩,渴望那种爆裂的快感。
写完以上内容,我会去想了想,如果我们想在列表的尾部加一个元素呢?
于是,我写了个小程序演习了一下:
-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行了。
既然是从尾部加,那么就让你要加的东西变成一个列表,然后再从头部,一个一个的加。
但是问题是那样的话,顺序反了,所以,要再写个反转的函数,给它掉个个。
我想可能得有好几种处理方法,这样效率是不是会低呢?不晓得。
写函数时,对于空表和非空表处理的常见性,让我有点吃惊。
这种[H|T]和[]的区别,erlang是能自己分清的——我本来以为只要是有两个参数的,不管什么类型它都分不清呢!
函数式编程的时候,状态是在参数里维护的,因为你不可能建太多的变量(当然它是不变的),比如说在遍历列表的时候,所以,只要你想变的时候,就调函数就好了,让函数来维护一个一致的状态。不管你调用函数多少次,都不会浪费资源,因为那是应该的。你的变化的状态在函数的参数之间传递和改变,你只要在适当的时候,返回变化好了的参数就可以了。
这算我的一点点体会吧!
写了上述东西之后,觉得有些意犹未尽,看了看getting started,发现我的写法没问题,是标准写法,效率也没问题。
那个list_max的例子引起了我的注意:
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).
差别是那个when,它替代了if,使得风格变得漂亮。
这种东西文档里说是guard,而中文翻译成了断言,很不恰当。
这种函数入口的选择,看似微小,实则非常的重要。
它弥补了动态语言的弱点,使得可以根据某些特性来选择进那个函数。
如果用if写的话,是这样:
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.
搞笑的是,那个Head =< Result_so_far,我开始写成<=,结果怎么也不对,我查了下才清楚,它居然写成那样!
分享到:
相关推荐
Erlang的文件操作API(如`file:list_dir/1`、`file:open/2`、`file:read_line/1`和`file:close/1`)是处理文件系统操作的核心部分。它们提供了一种安全且并发友好的方式来访问和操作文件。`filename:join/1,2`函数...
Erlang是一种用于构建并发、分布和容错系统的编程语言和运行时环境。Erlang拥有一个独特的语法和一套内置的数据类型,以及专门为并发编程设计的库。下面将详细介绍Erlang速查表中提到的一些关键知识点。 ### 变量和...
Functions in Erlang are defined by their name followed by a list of arguments enclosed in parentheses. The arity (number of arguments) is an important aspect that distinguishes functions with the ...
erlang代码: run () -> Number = receive I when is_integer ( I ) -> I S when is_list ( S ) -> { N , _Rest } = string : to_integer ( S ), N end , io : format ( " got int: ~p " , [ Number ]), Other = ...
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) ``` 然后启动Emacs,按`M-x package-refresh-contents`刷新包列表,接着运行`M-x package-install distel`安装Distel。 4. **...
- **调试**: 使用`M-x distel-debug`启动调试器,`C-c C-a`设置断点,`C-c C-r`运行程序,`C-c C-s`单步执行,`C-c C-n`和`C-c C-p`进入/退出函数。 ### 6. 高级使用技巧 - **自动同步**: 通过`distel-autosync`,...
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.19.rabbitmq37-generic-erlang$(erl -eval 'io:fwrite("~s~n", [erlang:system_info(otp_release)]).' -noshell)/rabbitmq-signing-key-...
- 验证状态:`chkconfig --list rabbitmq-server` - **启用管理插件**: - `rabbitmq-plugins enable rabbitmq_management` - 重启服务:`service rabbitmq-server restart` **步骤四:创建新用户** - 创建新...
\curl -sSL https://raw.githubusercontent.com/taylor/kiex/master/install | bash -s 它将安装在$ HOME / .kiex中。 用法 列出已安装的版本 kiex list 列出已知版本 kiex list known (或kiex list releases ) ...
RabbitMQ基于Erlang语言编写,因此安装RabbitMQ前需先安装Erlang。 1. **安装开发工具**:安装`gcc/g++`、`make`等开发工具。 ```bash sudo apt-get install build-essential ``` 2. **安装Erlang所需的关键库*...
为简单起见,它仅包含将在运行时评估的erlang术语。 {matcher,Match_Pattern,Keyword,Backend_List}。 {matcher,...}。 {default_matcher,Timeout,Backend_List} ... 例子: { matcher , " (?i)host: \\ s*( ...
- 解压后,将RabbitMQ的可执行文件移动到适当目录,如`/usr/local/`,并创建软链接以便于管理:`sudo mv rabbitmq_server-3.5.7 /usr/local/rabbitmq && sudo ln -s /usr/local/rabbitmq/sbin/rabbitmq-server /usr...
% input argument list, a single random number of the specified % TYPE and default parameters shown below is generated. If only % TYPE, M, and N are provided, the default parameters shown below % are ...
iex> is_list('Character list') true 集合与Enum模块 Elixir 提供了几种集合类型,如列表、映射、元组和集合。Enum 模块提供了处理列表的大量函数,例如遍历、过滤和转换: iex> numbers = [1, 2, 3, 4, 5] [1, 2...
在所有集群节点上确保操作系统、RabbitMQ版本和Erlang版本一致。 2. **共享存储** 集群需要共享存储,可以使用NFS或者设置共享磁盘。 3. **集群成员** 在每个节点上,启动RabbitMQ服务并添加其他节点为集群伙伴...
ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet ``` 3. **RabbitMQ**: RabbitMQ是一个基于AMQP协议的消息队列服务器,用于实现异步处理和解耦应用组件。离线安装RabbitMQ需要先安装Erlang环境,然后解压...
Thrift实现了C/S模式,使用代码生成工具根据接口定义文件生成服务器端和客户端代码,这样可以在不同的语言之间实现无缝的服务调用。用户在Thrift描述文件中声明服务后,这些服务会被编译成相应语言的代码文件,之后...
Leal's solution Leal提出的解决方案,可能是一种独特或创新的方法,值得学习和参考。 #### 22. More generic solution 更通用的解决方案意味着它能适应更广泛的情况,而不仅仅是当前问题。这通常需要抽象化和...
首先,Elixir是一种基于BEAM虚拟机的动态类型语言,它是 Erlang 的扩展,尤其适用于构建分布式、容错性和并发系统。Elixir采用了元编程和函数式编程的思维方式,这使得它在处理并发和并行计算时表现出色。 在...