【发布时间】:2015-11-30 15:04:05
【问题描述】:
我试图找到将以下有状态的命令式代码转换为纯函数表示的最优雅的方法(最好在 Haskell 中使用其 Monad 实现提供的抽象)。但是,我还不擅长使用变压器等组合不同的单子。在我看来,分析他人对此类任务的看法对自己学习如何做最有帮助。命令式代码:
while (true) {
while (x = get()) { // Think of this as returning Maybe something
put1(x) // may exit and present some failure representation
}
put2() // may exit and present some success representation
}
当get 返回Nothing 时,我们需要继续执行put2,当get 返回Just x 时,我们希望x 传递给put1,并且仅在@ 时短路987654331@ 失败或循环。基本上put1 和put2 可能会终止整个事情或移动到以下语句以某种方式改变底层状态。 get 可以成功并调用put1 并循环或失败并继续put2。
我的想法是这样的:
forever $ do
forever (get >>= put1)
put2
而我之所以要寻找类似的东西是因为(get >>= put1) 可以在get 没有任何返回或put1 终止时简单地短路。同样put2 终止外循环。但是我不确定如何将State 与必要的Maybe 和/或Either 混合以实现此目的。
我认为使用转换器来组合State 和其他单子是必要的,因此代码很可能不会那么简洁。但我想它也可能不会更糟。
欢迎任何关于如何优雅地实现翻译的建议。这与“Stateful loop with different types of breaks”的不同之处在于避免使用if、when、while 进行显式控制流,而是试图鼓励使用Maybe、Either 或其他一些方便的>>= 语义。此外,总有一种直接的方法可以将代码转换为函数式代码,但它很难被认为是优雅的。
【问题讨论】:
-
你也需要混合失败的“权力”。这看起来像
EitherT或MaybeT,因此您需要查看 monad 变压器堆栈。要么!如果你只是想探索,看看这个 monad:data M e s a = M { runM :: e -> Either e (s, a) }注意到它实例化了MonadState s。 -
尝试重写您的原始代码,使其不使用
exit()。您现在可以如何实现与此功能等效的功能吗? -
Stateful loop with different types of breaks 的可能重复项 - 区别在哪里?
-
它是原始问题的改进版本,不同之处在于删除控制流,而是直接链接操作,允许它们失败。现在交换的信息不仅仅是
True、False,而是Maybe something,从而产生了不同的链接。put1和put2似乎没有提供一种简单的重写方法,不会导致 main 函数返回。原始问题的答案确实涉及很多类似 if-then-else 的代码,这是尝试使用>>=的Maybe和Either代替。 -
我建议您首先在 Haskell 中手动编写整个内容(不要像
exit或特别是error这样的有趣业务)。这将使您更好地了解您想要实际需要支持的漂亮抽象。
标签: haskell functional-programming monad-transformers state-monad imperative-programming