functional-programming - 列表:在 Erlang 中具有副作用的映射
问题描述
我有一个 id 的批次(子列表)列表,我想遍历这个列表并为这批 id 中的每个 id 生成一个工作进程。这些工作人员中的每一个都将查询一些服务,获取结果并将其发送回调用者。简而言之,我想将 s 列表映射id
到通过这些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)))
在这种情况下,如您所见,我滥用map
功能,因为它被设计为无副作用。但我没有看到其他选择。有,foreach()
但它仅用于运行副作用并仅返回ok
,而在我的情况下,我也想保留列表的形状。在 Haskell 中有一个方便的类型类Traversable
,其traverse
功能正是这样做fmap
的:运行并同时允许您对每个项目执行操作(效果)。Erlang中有类似的东西吗?(smap
也许像?)。
解决方案
与 Haskell 不同,Erlang 不是一种纯函数式编程语言。作为推论,它没有对功能是否可以产生副作用进行限制。Traversable
在 Haskell 中,即使 I/O 子系统也无法破坏其纯度,这就是为什么在和Functor
(traverse
和)之间存在类型级别的区别,fmap
前者可以对容器的每个元素运行效果,而后者不能。在 Erlang 中没有这么明显的区别,因此,您可能有一个函数execute(Container) ->
,但您不知道它是否会运行效果,只需凝视它的签名。这就是为什么拥有map
和smap
(或traverse
,或任何你称之为的)在 Erlang 中没有意义,也不会带来任何价值。但是,使用lists:map
这种操作确实违反了map
应该是纯函数的契约。在这种情况下,我可能会建议您使用列表理解,在我看来这是一种更惯用的方式:
[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].
同样,在我自己的观点中,副作用是列表推导和lists:map()
. 当它们以上述方式使用时,我通常认为它们是 Haskell 的单子理解。
推荐阅读
- linq - 创建包含 linq 查询的异步方法
- apache-spark - 在 Apache Spark 中,同一 Stage 中的任务是否同时工作?
- r - 在 Windows 和 Linux 上为特定 PRNG 生成不同的随机数
- python - 将字典中的函数用于菜单
- visual-studio - 如何将 firebase ml 套件与 xamarin.forms 一起使用?
- python - 获取程序中的计算次数
- java - 将 view.jsp 中的日期传递给我的 Java Portlet
- python - 如何比较数据框中的两个字符串列表以获取任何匹配项以在 python 中获得 True 或 False?
- c# - 即使实际和预期匹配,断言也会失败
- excel - 有没有办法将电子表格中的特定列绑定到 GUI [VBA] 中的组合框