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

时间:2015-03-05 09:52:43

标签: monads defects

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

author writes

  

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

     

...

     
      
  • 防止可能因执行的不同阶段之间的混淆而产生的错误。
  •   

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

2 个答案:

答案 0 :(得分:0)

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

m

这为您的来电者提供了完全的自由(他们可以选择任何一个Monad的int imageScrollerWidth = ([self.setSpins count]+1) * (int)([self.imageDimensions[@"width"] integerValue] + 5); [self.spinScrollView setContentSize:CGSizeMake(imageScrollerWidth, self.spinScrollView.frame.size.height)]; self.spinScrollView.contentOffset = CGPointZero; ),同时拒绝为您的图书馆提供任何此类自由。这可以防止在其他纯文库中引入副作用,同时允许在呼叫者需要时产生副作用。

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

答案 1 :(得分:0)

效果分离

像普通类型一样,您可以分辨出 data 数据,而monad则可以使您分辨出 effects 的方法。

长生不老药

这里是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}获取并设置一个可变状态变量

我希望我在这里有单子,以防止出现以下错误:

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

您能发现错误吗?好吧,我只是写了一个只读值。 Elixir中没有什么可以阻止这一点。您不能将GenServer状态的某些部分标记为只读,而其他部分也可以读写。

Haskell:读者和国家

在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不具有此功能,并且可以忽略上述bug。

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