monad阻止的错误类别是什么?

问题描述 投票:1回答:2

我的理解是,对于do monad,每一步都有一个延续和一个闭包。

author writes

我们已经看到纯度,强类型和单子可以:

...

  • 防止可能由不同执行阶段之间的混淆引起的错误。

我的问题是:monad阻止的错误类别是什么?

monads defects
2个回答
0
投票

假设您编写了一个必须接收回调的算法。你不知道回调想要做什么,或者它能做什么。接受这种回调的最通用方法是接收如下函数:

Monad m => a -> m b

这为你的来电者提供了完全的自由(谁可以选择任何一个Monad的m),同时否认你的图书馆有这样的自由。这可以防止在其他纯库中引入副作用,同时如果调用者需要它们则允许发生副作用。

我以前在纯寄存器分配器中使用过这种模式。在该库中,我自己从不需要效果,但希望允许用户使用自己的效果(例如State)来创建新块和移动指令。


0
投票

效果分离

像普通类型给你一种区分数据的方法,monad给你一种区分效果的方法。

Elixir

以下是Elixir中的一个示例,它是一种基于Erlang的几乎纯函数式语言。这个例子来源于我工作中经常出现的真实情况。

def handle_call(:get_config_foo, _, state) do:
  {:reply, state.foo, state}
end

def handle_call(:get_bar, _, state) do:
  {:reply, state.bar, state}
end

def handle_call({:set_bar, bar}, _, state) do:
  {:reply, :ok, %{state | bar: bar}}
end

这定义了GenServer的API,它是一个小的Erlang节点,它包含一些state并允许您查询它以及更改它。第一个调用,:get_config_foo读取一个不可变的配置设置。第二组调用:get_bar{:set_bar, bar}获取并设置一个可变状态变量。

我希望我在这里有monad,以防止以下错误:

def handle_call({:set_bar, bar}, _, state) do:
  {:reply, :ok, %{state | foo: bar}}
end

你能发现错误吗?好吧,我刚刚写了一个readonly值。 Elixir中的任何内容都无法阻止这一点。您不能将GenServer状态的某些部分标记为只读,而其他部分也可以读写。

哈斯克尔:读者和国家

在Haskell中,您可以使用不同的monad来指定不同类型的效果。这里是只读状态(Reader)和读写状态:

data Reader r a = Reader (r -> a)
data State s a = State (s -> (a, s))

Reader允许您访问配置状态r以返回一些值aState允许您读取状态,返回一些值并修改状态。两者都是monad,这实际上意味着您可以以强制方式顺序链接这些状态访问。在Reader中,您可以先读取一个配置设置,然后(根据第一个设置),读取另一个设置。在State中,您可以阅读状态,然后(根据您阅读的内容)进一步修改它。但是在执行它时,你永远不能修改Reader中的状态。

确定性影响

让我再说一遍。将几个调用绑定到Reader可以确保您永远不会修改它们之间的读取器状态。如果你有getConfigFoo1 :: Reader Config Foo1getConfigFoo2 :: Foo1 -> Reader Config Foo2并且你做了getAllConfig = getConfigFoo1 >>= getConfigFoo2,那么你可以确定两个查询都将运行在相同的Config上。 Elixir没有此功能,并且允许上述错误被忽视。

其他有用的效果是Writer(只写状态,例如日志记录)和Either(异常处理)。当你有Writer而不是ReaderState时,你可以确定你的状态只被附加到。当你有Either时,你就知道可能发生的异常类型。这比使用IO进行日志记录和异常处理要好得多。

© www.soinside.com 2019 - 2024. All rights reserved.