Functional programming 列表:在Erlang中具有副作用的映射

Functional programming 列表:在Erlang中具有副作用的映射,functional-programming,erlang,otp,map-function,traversable,Functional Programming,Erlang,Otp,Map Function,Traversable,我有一个id的批(子列表)列表,我想迭代这个列表,并为id批中的每个id生成一个工作进程。这些工作人员中的每个人都将查询某些服务,得到结果并将其发送回调用方。简单地说,我想将ids的列表映射到一个数据列表,我通过这些ids获得这些数据。我成功地做到了这一点,但我相信这是一种非传统的方式: lists:map(fun(Ids) -> Pids = [spawn_link(fun() -> Result = [...] % Here goes a side-effect oper

我有一个id的批(子列表)列表,我想迭代这个列表,并为id批中的每个id生成一个工作进程。这些工作人员中的每个人都将查询某些服务,得到结果并将其发送回调用方。简单地说,我想将
id
s的列表映射到一个数据列表,我通过这些
id
s获得这些数据。我成功地做到了这一点,但我相信这是一种非传统的方式:

lists:map(fun(Ids) ->
Pids = [spawn_link(fun() ->
    Result = [...] % Here goes a side-effect operation (http request)
    Self ! {received_data, process(Result)}
end) || Id <- Ids],
[receive {received_data, Data} -> Data end || _Pid <- Pids],
end, JobChunks)))
[begin
    Pids = [spawn_link(fun() ->
        % Side-effect operation which worker performs
    end) || Id <- Ids],
   [receive {received_data, Data} -> Data end || _Pid <- Pids]
end || Ids <- JobChunks].
列表:地图(乐趣(Ids)->
Pids=[spawn_链接(fun()->
结果=[…]%出现了一个副作用操作(http请求)
Self!{已接收_数据,处理(结果)}

(完)| | Id Data end | | | | | u Pid与Haskell不同,Erlang不是一种纯函数式编程语言。作为推论,它不会限制函数是否会产生副作用。在Haskell中,即使是I/O子系统也不能破坏其纯度,这就是为什么在类型级别上存在
可遍历之间的区别
Functor
遍历
fmap
),前者可以对容器的每个元素产生效果,后者不能。在Erlang中没有这样明确的区别,因此,您可能有一个函数
执行(容器)->
,你只需盯着它的签名就不知道它是否会运行效果。这就是为什么要使用
map
smap
(或者
遍历
,或者你管它叫什么)在Erlang中没有任何意义,也不会带来任何价值。但使用
list:map
进行此类操作确实会打破
map
的约定,这应该是一个纯粹的函数。在这种情况下,我可能建议您使用列表理解,在我看来这是一种更惯用的方式:

lists:map(fun(Ids) ->
Pids = [spawn_link(fun() ->
    Result = [...] % Here goes a side-effect operation (http request)
    Self ! {received_data, process(Result)}
end) || Id <- Ids],
[receive {received_data, Data} -> Data end || _Pid <- Pids],
end, JobChunks)))
[begin
    Pids = [spawn_link(fun() ->
        % Side-effect operation which worker performs
    end) || Id <- Ids],
   [receive {received_data, Data} -> Data end || _Pid <- Pids]
end || Ids <- JobChunks].
[开始]
Pids=[spawn_链接(fun()->
%工人执行的副作用操作

(完)| | Id Data end | | | | | u Pid与Haskell不同,Erlang不是一种纯函数式编程语言。作为推论,它不会限制函数是否会产生副作用。在Haskell中,即使是I/O子系统也不能破坏其纯度,这就是为什么在类型级别上存在
可遍历之间的区别
Functor
遍历
fmap
),前者可以对容器的每个元素产生效果,后者不能。在Erlang中没有这样明确的区别,因此,您可能有一个函数
执行(容器)->
,你只需盯着它的签名就不知道它是否会运行效果。这就是为什么要使用
map
smap
(或者
遍历
,或者你管它叫什么)在Erlang中没有任何意义,也不会带来任何价值。但使用
list:map
进行此类操作确实会打破
map
的约定,这应该是一个纯粹的函数。在这种情况下,我可能建议您使用列表理解,在我看来这是一种更惯用的方式:

lists:map(fun(Ids) ->
Pids = [spawn_link(fun() ->
    Result = [...] % Here goes a side-effect operation (http request)
    Self ! {received_data, process(Result)}
end) || Id <- Ids],
[receive {received_data, Data} -> Data end || _Pid <- Pids],
end, JobChunks)))
[begin
    Pids = [spawn_link(fun() ->
        % Side-effect operation which worker performs
    end) || Id <- Ids],
   [receive {received_data, Data} -> Data end || _Pid <- Pids]
end || Ids <- JobChunks].
[开始]
Pids=[spawn_链接(fun()->
%工人执行的副作用操作

end)| | | Id Data end | | | u Pid我喜欢@Oleksandr answer,但是在列表中使用begin..end块感觉有点脏。我会使用函数来实现这一点

还需要注意的是,他的回答的第二部分并不能保证尊重原始列表的顺序(即,它将只包含相同的元素,但它们将根据它们到达的顺序进行排序)。这对您来说可能没问题,但如果您希望能够匹配输入(ID)和输出(结果),您必须使用选择性接收,我将在下面向您展示

因此,我将在没有OTP的情况下实现它(因为您也没有使用OTP):

your_函数()->
[进程块(ID)| | ID
Pids=[spawn_side_effect_fun(Id)| Id
Self!{已接收\u数据,Self(),您的\u副作用\u操作()}
(完)。
获取(Pid)的\u结果\u->
接收
%%这里是Pid上的模式匹配
%%所以我们得到这个特定Pid的结果
%%因此,顺序保留在最终列表中。
{接收的_数据,Pid,数据}->数据
终止

注意这里没有处理任何错误也很重要。因为没有捕获出口,生成的进程中的错误只会杀死主进程。

我喜欢@Oleksandr answer,但是在列表中使用begin..end块感觉有点脏。我会使用函数来实现这一点

还需要注意的是,他的回答的第二部分并不能保证尊重原始列表的顺序(即,它将只包含相同的元素,但它们将根据它们到达的顺序进行排序)。这对您来说可能没问题,但如果您希望能够匹配输入(ID)和输出(结果),您必须使用选择性接收,我将在下面向您展示

因此,我将在没有OTP的情况下实现它(因为您也没有使用OTP):

your_函数()->
[进程块(ID)| | ID
Pids=[spawn_side_effect_fun(Id)| Id
Self!{已接收\u数据,Self(),您的\u副作用\u操作()}
(完)。
获取(Pid)的\u结果\u->
接收
%%这里是Pid上的模式匹配
%%所以我们得到这个特定Pid的结果
%%因此,顺序保留在最终列表中。
{接收的_数据,Pid,数据}->数据
终止
注意这里没有处理任何错误也很重要。因为你没有捕获出口,所以派生进程中的错误只会杀死主进程