Erlang 编程问题

Erlang 语言编程问题: 一家具有创新理念的新公司计划让顾客在网上订购食品杂货,然后用卡车送货。他们决定将这项服务称为“WeePod”(也是需要的编程文件名)。你的目标是编写一个Erlang服务器来帮助运行该服务。服务器应该拥有增加/删除商品列表和客户购物车。命令应该包括:

show_shelves
Returns a list of {=item name=, =price=} pairs.
返回所有商品(商品名字,价格)的列表

{add_item, =item name=, =price=}
Puts the new item on shelve (or changes the price for the existing item).
增加新商品(或者改变现有商品的价格)
{choose, =item name=, =count=}
Places =count= many =item name='s in your shopping cart.
将商品名字和价格加入购物车
{remove, =item name=}
Removes all =item name='s (if any) from your shopping cart.
删除所有在购物车里的商品
show_basket
Returns a list of {=item name=, =count=} pairs.
输出购物篮中商品名字+数量
checkout
Returns total price of items in your shopping cart.
输出购物篮中商品总额

除了服务器所需的代码之外,还应该提供一个向服务器发送消息的简单函数。(例子最后有写)

如下是问题给的简单示例:

-module(weepod_alpha).
-export([start/0, send_wait/2]).

start() -> spawn(fun init/0).

init() ->
put({item, lettuce}, 1.50),
put({item, cupcake}, 0.75),
put({item, soup}, 2.35),
put(cart, []),
loop().

add_items(Name, Count, []) -> [{Name, Count}];
add_items(Name, Count, [{Name, C}|L]) -> [{Name, C+Count}|L];
add_items(Name, Count, [H|L]) -> [H|add_items(Name, Count, L)].

shelf_list() ->
K = get(),
[{N,get(E)} || {{item, N}=E, _} <- K].

loop() ->
receive
{From, show_shelves} ->
From ! {self(), shelf_list()}, loop();
{From, {choose, Name, Count}} ->
put(cart, add_items(Name, Count, get(cart))),
From ! {self(), ok}, loop();
{From, Other} ->
From ! {self(), {error, Other}}, loop()
end.

% core client function
send_wait(Pid, Request) ->
Pid ! {self(), Request},
receive
{Pid, Response} -> Response
end.

第1个回答  2018-12-29
Erlang 是一种多用途的编程语言,主要用于开发并行和分布式系统。本系列文章的第 1 部分介绍了 Erlang 及其函数编程风格与其他编程范式的对比情况,例如命令式、过程和面向对象的编程。在第 2 部分中,您将使用部分高级特性和功能,首先从基本函数开始,随后介绍并行编程、进程和消息传递。这些内容结合在一起,共同支持分布式编程,也就是 Erlang 的一种强大的特性。
并行编程
实现在一个程序内同时执行多个进程的能力(而非同时运行多个程序)始终要求人们改变使用传统函数编程语言时的编程方法。这种并行性(或多线程)问题在于确保您希望为其更新信息的线程,仅影响正在处理的数据和信息。举例来说,您不希望一个更新单个文件的进程多次执行,因为这可能带来文件在处理过程中被损坏的风险。
Erlang 采用了使所有程序保持并行的方法,而且组件(函数和模块)均不共享数据。数据使用消息在组件之间交换。利用消息可限制独立组件修改数据的方式,从而有助于消除并行数据修改问题。这种方法不再直接更改数据,而是发送消息来更新数据,因此也使隔离和并行更新更为困难。Erlang 还遵循操作必将失败的原则,因此提供了一种能够处理错误并在必要时从中恢复的系统。
Erlang 在内部通过创建称为进程的小型轻量级执行来处理并行性问题。不同于 C 等其他主流语言,这些进程并非构建在本地操作系统进程或线程模型之上,而是由 Erlang 虚拟机内部创建和管理。这允许各进程在内存和 CPU 需求方面比本地 OS 线程更为轻量。此外,由于 Erlang 通过自动创建和使用众多小型进程执行操作,因此即便相对较为简单的程序往往也要运行成千上万个甚至数百万个进程。
并行模型内置于 Erlang 之中,因此大量进程的管理是 Erlang 工作方式的关键组成部分。用于在进程间发送数据的消息传递系统也采用了内置形式,并设计为以非常有效的方式向任意进程分发消息,而无论当前正在运行的进程的数量如何。作为消息实现的一种附带收益,消息不仅可内部发送,还可跨网络发送,允许 Erlang 跨多个实例共享消息,从而支持多台机器间的分布式编程。

进程
Erlang 进程系统是轻量级的,进程的创建直观而简单,由于不存在开销,因此也几乎没有理由担心其影响。这就意味着您可以出于任何对应用程序有益的原因来创建新进程。
在实践中,您可以调用内置函数 spawn() 来创建进程,其调用结构如下: PID = spawn(module, function, arguments),其中 module 是模块名称、function 是函数名称、arguments 是要提供给函数的参数列表。返回值(上例中的 PID)是进程标识符。
举例来说,在本系列上一期文章中,可以使用以下格式将我们创建的 Fibonacci 函数作为新进程调用:PID = spawn(fib,printfibo,[10])。
请注意,spawn() 的最后一个参数是仅有一个元素的列表,而非在直接调用函数时使用的单一参数。结果是一个新进程,将按照调用函数的方式来执行函数: fib:printfibo(10)。
spawn() 创建的新进程将在终止之前继续执行,可能正常终止(即无错误),也可能非正常终止(即发生了某些错误)。
实际的生成进程本身不会失败,即便您调用的函数不存在也是如此。这能减少在代码中测试生成进程的需要。除了 Erlang shell 中的错误以外,其他进程中的错误将由错误记录程序处理和记录,这是一个处理错误报告的内置进程。
在典型使用中,进程用于支持并行性。在上述 Fibonacci 样例中,在另一个进程内运行printfibo() 函数不会得到有用的返回值。但是,如果您希望生成一个新进程,例如基本 fibo()函数,同时向该进程发送信息并接收该进程提供的信息,又该如何?
内置的消息传递系统可处理这样的交互。

消息传递
Erlang 中的消息传递系统是 Erlang 执行环境的另一个内置部分,它与进程系统协同工作,支持有效地交换数据和消息。
每个进程都将获得一个“邮箱”,其他进程可向此邮箱发送消息。消息按照发送顺序存储,也就是说如果您从一个进程向另一个进程依次发送 A 和 B 两条消息,则消息 A 将先显示在邮箱中,消息 B 紧随其后。由于进程系统有着并行的本质,因此除了同一个进程发送的消息的独立顺序之外,多个进程发送到单独一个进程的多条消息的顺序不会按照任何特定方式排序。
要向一个进程发送一条消息,您需要了解希望与之通信的进程的进程 ID。随后可使用结构: Pid ! Message,其中 Pid 是进程 ID, Message是任意 Erlang 数据类型。
要从一个进程内接收一条消息,可使用 receive 语句。在 receive 语句内,使用模式匹配根据消息内容来确定要执行哪些操作。如果匹配成功,则从邮箱接收消息,消息参数通过绑定到匹配中的变量提供,并执行相应的子句。
举例来说,根据提供 “store” 原子(atom)和一个值的消息进行匹配的代码!本回答被网友采纳
相似回答