Erlang
环境安装 + 语法练习
- 安装环境
- 菜鸟教程过一遍语法 语法
练习
hh.erl
-module (hh).
-export ([start/0]).
-import (io, [fwrite/1]).
-record (person, {name = "", id, age, email}).
-record (employee, {person, employee_id}).
-include ("head.hrl").
-define (a, 1).
-define (add(X, Y), {X + Y}).
start() ->
% 输出
io:format("hello world! ~n"),
io:format("hh X is ~w and string is ~s. ~n", [22, "hhhhh"]),
io:format("tuple : ~p and list : ~p ~n", [{1, "22", 22}, [3, 2, {2, 2, 3}]]),
io:format("float is ~.3f ~.9f hh ~n", [2.233232, 2.33333333333333]),
% 数字
io:format("~w ~n", [2 + 2]),
% 原子 - 看做一个静态变量
fwrite(atom1),
fwrite("\n"),
fwrite('hh \n'),
% Boolean
io:format("~p ~n", [2 < 3]),
% 测试如何使用变量
X = 1,
Y = 2,
I = 1,
J = I + 1,
% i = I + 2,不能有小写开头的变量 ! ! chatgpt给出的错误答案误导了我
io:format("X : ~w, Y : ~w, i : ~w, j : ~w. ~n", [X, Y, I, J]),
% 位串
Bin1 = <<10, 20, 30>>,
OinList = binary_to_list(Bin1),
io:format("Bin1 to List : ~p ~n", [OinList]),
% ~e 与 ~f
io:format("~f, ~e, ~p ~n", [50.2, 0.333, 12]),
% 算术运算符
io:format("~w, ~w, ~w, ~w, ~w, ~w ~n", [1 + 1, 1 - 1, 1 * 1, 1 / 2, 1 div 1, 10 rem 3]),
% 关系运算符
io:format("~p, ~p, ~p, ~p, ~p, ~p ~n", [1 == 1, 1 /= 1, 1 > 1, 1 < 1, 1 >= 1, 1 =< 1]),
% 逻辑运算符 - bool
io:format("~p, ~p, ~p, ~p ~n", [true and true, false or true, not false, false xor true]),
% 逻辑运算符 - 数字
io:format("~p, ~p, ~p, ~p ~n", [1 band 1, 1 bor 1, bnot 1, 1 bxor 22]),
% while循环, 只能通过递归实现
L = [1, 2, 3, 4],
while(L),
% for
for(5),
for(1, 5),
forx(1, 5),
Array = ["22", [222, 111, 2], {22, 2, 1, {2, 1, 1}}],
for_list(Array),
% 条件语句
io:format("~p ~n", [max_hh(3, 2)]),
io:format("~p ~n", [max_(144, 44, 333)]),
io:format("~p ~n", [is_five(5)]),
% 匿名函数
Fn = fun() -> io:format("hh ~n") end,
Fn(),
% 递归
Fac = fac(8),
io:format("~w ~n", [Fac]),
io:format("~w ~w ~n", [fib(10), fib_(10)]),
io:format("~p ~n", [len([1, 1, 1])]),
io:format("~p ~n", [tail_len([1, 1, 1])]),
io:format("~p ~n", [duplicate(3, 1)]),
io:format("~p ~n", [reverse([1, 2, 3, 4, 5])]),
% lists库的用法之一
ListA = [1, 2, 3, [2, 2, 2]],
io:format("~w ~w ~n", [lists:nth(1, ListA), lists:nth(1, lists:nth(4, ListA))]),
People = [{john, 25}, {john, 30}, {mary, 230}, {mary, 25}, {adam, 20}, {eve, 25}],
SortedByAgeAndName = lists:sort(fun({N1, A1}, {N2, A2}) ->
case N1 =:= N2 of
true -> A1 < A2;
false -> N1 < N2
end
end,
People),
io:format("~p ~n", [SortedByAgeAndName]),
%数字
io:format("~w ~f ~e ~n", [3, float(3), 32.1]),
%列表以及常用方法
% all(fun, list) 判断list中的所有元素是否满足fun
AllList = [1, 2, 3],
Predicate = fun(E) -> E rem 2 == 0 end,
io:format("~p ~n", [lists:all(Predicate, AllList)]),
io:format("~p ~n", [lists:any(Predicate, AllList)]),
io:format("~p ~n", [lists:append([1, 2, 3], [4, 5])]),
io:format("~p ~n", [lists:delete(2, [1, 2, 3])]),
io:format("~p ~n", [lists:droplast([1, 2, 3, 4, 5])]),
io:format("~p ~n", [lists:duplicate(5, [2, 1])]),
io:format("~p ~p ~n", [lists:last([1, 2, 3]), lists:max([2, 3, -1, 99])]),
io:format("~p ~n", [lists:member(2, [1, 1, 1, 2 + 0])]),
io:format("~p ~n", [lists:merge([[1, 2, 99], [3, 33], [2]])]),
Nth = [1, 2, 3, 4],
io:format("~p ~n", [lists:nth(2, Nth)]),
% 文件
{ok, File} = file:open("io_test.txt", [read]),
Txt = file:read(File, 1024 * 1024),
io:format("~p ~n", [Txt]),
%原子
io:format("~p ~n", [is_atom(s_11)]),
io:format("~p ~n", [atom_to_list(s_11)]),
io:format("~p ~n", [list_to_atom("list")]),
io:format("~p ~n", [atom_to_binary('Erlang', utf8)]),
io:format("~p ~n", [binary_to_atom(<<"erlang">>, latin1)]),
%映射, map
M1 = #{name => lele, age => 12},
M2 = #{name => 1, "b" => 2},
io:format("~p ~n", [M1]),
io:format("~p ~n", [maps:get('name', M1)]),
io:format("~p ~n", [maps:from_list([{"a", 1}])]),
io:format("~p ~n", [maps:find('name', M1)]),
io:format("~p ~n", [maps:keys(M1)]),
M3 = maps:merge(M1, M2),
io:format("M3 : ~p ~n ~p ~n", [M3, maps:get(name, M3)]),
io:format("~p ~n", [maps:put(h, h, M3)]),
io:format("~p ~n", [maps:remove(h, M3)]),
io:format("~p ~n", [map_size(M3)]),
% 元组 tuple
P = {1, 2, {2, 3, "33"}, 33},
io:format("~p ~n", [tuple_size(P)]),
io:format("~p ~n", [list_to_tuple(tuple_to_list(P))]),
% record 记录
Person = #person{name = "lele", age = "18", id = 1, email = "hh"},
io:format("~p ~p ~p ~n", [Person, Person#person.age, Person#person.name]),
Person1 = Person#person{name = "fluent"},
io:format("~p ~p ~p ~n", [Person1, Person1#person.age, Person1#person.name]),
Employee = #employee{person = #person{name = "hh", age = 11, id = 1, email = "hh"}, employee_id = 1},
io:format("~p ~n", [Employee#employee.employee_id]),
io:format("~p ~n", [Employee#employee.person#person.name]),
% 列表推导式
io:format("~p ~n", [[dis(A) || A <- [1, 2, 3, 4]]]),
% 异常
exception_demo1(),
exception_demo2(),
io:format("~n ~p ~n", [exception_demo3()]),
% 宏
macros_demo1(),
macros_demo2(),
macros_demo3(),
% 头文件
User1 = #user{name = "aa3", age = 5},
User2 = #user{name = "aa1", age = 2},
User3 = #user{name = "aa3", age = 3},
io:format("~p ~p ~n", [User1, User1#user.name]),
Dept = #dept{users = [User1, User2, User3], count = 3},
io:format("~p ~p ~n", [Dept, Dept#dept.users]),
UserLists = Dept#dept.users,
FirstUser = lists:nth(1, UserLists),
io:format("~p ~n", [FirstUser#user.name]),
RecordSortedByNameAndAge = lists:sort(fun({U1, N1, A1}, {U2, N2, A2}) ->
case N1 =:= N2 of
true -> A1 < A2;
false -> N1 < N2
end
end, UserLists),
io:format("~p ~n", [RecordSortedByNameAndAge]),
fwrite("end").
dis(X) -> X.
while(L) -> while(L, 0).
while([], Count) -> Count; % 递归的出口
while([H|T], Count) -> % 正常情况的执行
io:format("Count : ~w ~p ~p. ~n", [Count, H, T]),
while(T, Count + 1).
for_list([]) -> ok;
for_list([H|T]) ->
io:format("~p ~n", [H]),
for_list(T).
for(X, N) ->
if X > N -> ok;
true ->
io : format("X : ~w ~n", [X]),
for(X + 1, N)
end.
forx(N, N) -> io:format("~w ~n", [N]), ok;
forx(X, N) ->
io:format("~w ~n", [X]),
forx(X + 1, N).
for(0) ->
[];
for(N) when N > 0 ->
io:fwrite("Hello~n"),
for(N-1).
max_hh(X, Y) ->
if X > Y -> 1;
X == Y -> 0;
true -> -1
end.
max_(X, Y, Z) ->
if X >= Y ->
if X >= Z -> X;
true -> Z
end;
true ->
if Y >= Z -> Y;
true -> Z
end
end.
is_five(X) ->
case X of
5 -> true;
_ -> false
end.
fac(0) -> 1;
fac(N) -> N * fac(N - 1).
fib(0) -> 1;
fib(1) -> 1;
fib(N) -> fib(N - 1) + fib(N - 2).
fib_(N) when N == 1 -> 1;
fib_(N) when N == 0 -> 1;
fib_(N) when N > 1 -> fib_(N - 1) + fib_(N - 2).
len([]) -> 0;
len([_|T]) -> 1 + len(T).
tail_len(List) -> tail_len(List, 0).
tail_len([], Acc) -> Acc;
tail_len([_|T], Acc) -> tail_len(T, Acc + 1).
duplicate(0, _) -> [];
duplicate(N, Term) when N > 0 ->
io:format("~w ~n", [Term]),
[Term|duplicate(N - 1, Term)].
reverse(L) -> reverse(L, []).
reverse([], Acc) -> Acc;
reverse([H|T], Acc) -> reverse(T, [H|Acc]).
generate_exception(1) -> a;
generate_exception(2) -> throw(a);
generate_exception(3) -> exit(a);
generate_exception(4) -> {'EXIT', a};
generate_exception(5) -> erlang:error(a);
generate_exception(6) ->
try 1 / 0 of
Val -> {normal, Val}
catch
throw:X -> {thrown, X};
exit:X -> {exited, X};
error:X -> {error, X}
end.
exception_demo1() ->
io:format("~p ~n", [[catcher(I) || I <- [1, 2, 3, 4, 5, 6]]]).
exception_demo2() ->
io:format("~p ~n", [[{I, (catch generate_exception(I))} || I <- [1, 2, 3, 4, 5]]]).
exception_demo3() ->
try generate_exception(5)
catch
error:X ->
{X, hh}
end.
catcher(N) ->
try generate_exception(N) of
Val -> {N, normal, Val}
catch
throw:X -> {N, caught, thrown, X};
exit:X -> {N, caught, exited, X};
error:X -> {N, caught, error, X}
end.
macros_demo1() ->
io:format("~p ~n", [?a]).
macros_demo2() ->
io:format("~p ~n", [?add(1, 2)]).
-ifdef(a).
macros_demo3() ->
io:format("defined ~n").
-else.
macros_demo3() ->
io:format("not defined ~n").
-endif.
hear.hrl
-record (user, {name = "", age = 18}).
-record (dept, {users = [], count}).
-define (HH, HH).
语法练习 + 熟悉数据结构
- OJ, 但是输入输出不习惯, 写了几题就没写了.
- AcWing语法题 20道
code
-module(practise).
-export([start/0]).
start() ->
io:format("~p ~n", [a_plus_b(1, 2)]),
io:format("~p ~n", [sub_(5, 6, 7, 8)]),
io:format("~p ~n", [distance_(1, 7, 5, 9)]),
io:format("~p ~n", [choose_money(576)]),
io:format("~p ~n", [convert_time(556)]),
io:format("~p ~n", [check_multiple(6, 24)]),
io:format("~p ~n", [snack(3, 2)]),
io:format("~w ~n", [choose_section(99)]),
io:format("~p ~n", [game_time(2, 16)]),
% 传统if 与 模式匹配
io:format("~p ~n", [animal1("vertebrado", "mamifero", "onivoro")]),
io:format("~p ~n", [animal2("vertebrado", "mamifero", "onivoro")]),
io:format("~w ~n", [get_even(100)]),
io:format("~w ~n", [count_positive_number([1, -1, 2, 3, 4])]),
io:format("~w ~n", [increasing_seq(10)]),
io:format("~w ~n", [approximate_number(6)]),
print_diamond(5),
io:format("~w ~n", [convert_negative_number([1, -1, 2, -2])]),
io:format("~w ~n", [sum_or_average(2, [[1, 2, 3], [2, 3, 4]], "M")]),
io:format("~w ~n", [get_str_len("2 2")]),
io:format("~c ~n", [first_once_char("ancdewasad")]),
ak.
a_plus_b(A, B) -> A + B.
sub_(A, B, C, D) -> (A * B) - (C * D).
distance_(X1, Y1, X2, Y2) -> math:sqrt((X2 - X1) * (X2 - X1) + (Y2 - Y1) * (Y2 - Y1)).
choose_money(N) ->
_100 = N div 100,
_50 = (N - _100 * 100) div 50,
_10 = (N - _100 * 100 - _50 * 50) div 10,
_5 = (N - _100 * 100 - _50 * 50 - _10 * 10) div 5,
_2 = (N - _100 * 100 - _50 * 50 - _10 * 10 - _5 * 5) div 2,
_1 = (N - _100 * 100 - _50 * 50 - _10 * 10 - _5 * 5 - _2 * 2),
[_100, _50, _10, _5, _2, _1].
convert_time(N) ->
_h = N div 3600,
_min = (N - _h * 3600) div 60,
_sec = N - _h * 3600 - _min * 60,
[_h, _min, _sec].
check_multiple(X, Y) -> (X rem Y =:= 0) or (Y rem X =:= 0).
snack(X, Y) ->
M = #{1 => 4.00, 2 => 4.50, 3 => 5.00, 4 => 2.00, 5 => 1.50},
maps:get(X, M) * Y.
choose_section(X) ->
if (X >= 0) and (X =< 25) -> [0, 25];
(X > 25) and (X =< 50) -> [25, 50];
(X > 50) and (X =< 75) -> [50, 75];
(X > 75) and (X =< 100) -> [75, 100];
true -> []
end.
game_time(X, Y) ->
if X < Y -> Y - X;
X == Y -> 24;
true -> Y + 24 - X
end.
animal1(_1, _2, _3) ->
if _1 =:= "vertebrado" ->
if _2 =:= "ave" ->
if _3 =:= "carnivoro" -> "aguia";
true -> "pomba"
end;
true ->
if _3 =:= "onivoro" -> "homem";
true -> "vaca"
end
end;
true ->
if _2 =:= "inseto" ->
if _3 =:= "hematofago" -> "pulga";
true -> "lagarta"
end;
true ->
if _3 == "hematofago" -> "sanguessuga";
true -> "minhoca"
end
end
end.
animal2("vertebrado", "ave", "carnivoro") -> "aguia";
animal2("vertebrado", "ave", _) -> "pomba";
animal2("vertebrado", _, "onivoro") -> "homem";
animal2("vertebrado", _, _) -> "vaca";
animal2(_, "inseto", "hematofago") -> "pulga";
animal2(_, "inseto", _) -> "lagarta";
animal2(_, _, "hematofago") -> "sanguessuga";
animal2(_, _, _) -> "minhoca".
get_even(N) ->
[X || X <- lists:seq(1, N), X rem 2 == 0].
count_positive_number(Nums) ->
length([I || I <- Nums, I > 0]).
increasing_seq(N) -> [I || I <- lists:seq(1, N)].
approximate_number(N) -> [I || I <- lists:seq(1, N), N rem I =:= 0].
print_diamond(N) ->
[print_star(I) || I <- lists:seq(1, N - 1)],
print_star(N),
[print_star(I) || I <- lists:reverse(lists:seq(1, N - 1))],
ok.
print_star(N) -> io:format("~s ~n", [lists:flatten(["*" || _ <- lists:seq(1, N)])]).
convert_negative_number(N) ->
[convert_to_one(I) || I <- N].
convert_to_one(X) ->
if X < 0 -> 1;
true -> X
end.
sum_or_average(L, N, Op) ->
case Op of
"M" -> lists:sum(lists:nth(L, N)) / length(lists:nth(L, N));
true -> lists:sum(lists:nth(L, N))
end.
get_str_len(N) -> length(N).
first_once_char(N) ->
F = fun(V,L) -> length(lists:filter(fun(E) -> E == V end, L)) end,
lists:nth(1, [X || X <- N, F(X, N) == 1]).
简单的进程使用以及Socket
%% 进程练习
-module(process).
-export([start/0, call/2]).
call(Arg1, Arg2) ->
io:format("~s ~s ~n", [Arg1, Arg2]).
start() ->
Pid = spawn(?MODULE, call, ["hh", "process"]),
register(myprocess, Pid),
io:format("~p ~n", [registered()]),
io:format("~p ~n", [whereis(myprocess)]),
io:format("~p ~n", [Pid]),
io:format("~p ~n", [is_process_alive(Pid)]),
io:format("~p ~p ~n", [is_pid(Pid), is_pid(hh)]),
io:format("~p ~n", [pid_to_list(Pid)]),
io:format("~p ~n", [self()]),
ok.
%% socket练习1
-module(hw).
-export([start/0]).
start() ->
send(),
rece(),
ok.
send() ->
{ok, Socket} = gen_udp:open(8800),
io:format("~p ~n", [Socket]),
io:format("~p ~n", [gen_udp:send(Socket, "localhost", 8800, "hh")]),
ok.
rece() ->
{ok, Socket} = gen_udp:open(8789),
io:fwrite("~p ~n",[Socket]),
io:fwrite("~p ~n",[gen_udp:send(Socket,"localhost",8789,"Hello")]),
io:fwrite("~p ~n",[gen_udp:recv(Socket, 20)]).
%% socket练习2
-module(socket_).
-export([start/0, client/1]).
start() ->
% 猜测 spawn/1 为运行传入的参数
spawn(fun() -> server(4000) end).
server(Port) ->
% open/2 第一个参数为端口号, 第二个参数为发送的数据类型,{active, false}:表示该套接字不会自动接收数据包。相反,必须使用gen_udp:recv函数显式地接收数据包。
{ok, Socket} = gen_udp:open(Port, [binary, {active, false}]),
io:format("server open socket : ~p ~n", [Socket]),
loop(Socket).
loop(Socket) ->
%%Erlang中的inet模块(即网络模块)提供了许多用于创建和管理网络连接和协议的函数。常用的inet库方法包括:
%%inet:getaddr/1:将主机名解析为一个或多个IP地址。
%%inet:gethostbyname/1:将主机名解析为第一个可用的IP地址。
%%inet:gethostname/0:获取本地主机名。
%%inet:getifaddrs/0:获取本地所有网络接口的信息。
%%inet:setopts/2:设置套接字选项,如{active, true}以启用套接字上的活动模式,并自动通知进程有数据到达。
%%inet:open/2:打开TCP套接字并返回套接字描述符。
%%inet:peername/1:获取与给定套接字关联的远程端点名称(如IP地址和端口号)。
%%此外,inet模块还提供了许多其他与网络编程相关的函数,例如支持IPv6的inet6模块,可以使用inet:setopts/2设置和检索更多的套接字选项,并提供相应的协议簇处理函数%
inet:setopts(Socket, [{active, once}]),
receive
{udp, Socket, Host, Port, Bin} ->
io:format("server receive : ~p ~n", [Bin]),
gen_udp:send(Socket, Host, Port, Bin), %send 给谁客户端
loop(Socket)
end.
client(Msg) ->
{ok, Socket} = gen_udp:open(0, [binary]),
io:format("client opened socket : ~p ~n", [Socket]),
ok = gen_udp:send(Socket, "localhost", 4000, Msg),
Value = receive
{udp, Socket, _, _, Bin} ->
io:format("client receive : ~p ~n", [Bin])
after 2000 -> 0 % 处理超时情况
end,
gen_udp:close(Socket),
Value.
- 确定学习《Erlang趣学指南》, 着重学习没有见过的用例与方法
Reminder应用
- 熟悉一些概念性的东西
- 编写reminder应用
数据结构 + 重启器 + OTP
- 复习erlang数据结构, orddict dict gd_trees等等
- 手写重启器
- 学习OTP