gpt4 book ai didi

language-agnostic - 单子(monad)——它们在哪里是必要的?

转载 作者:行者123 更新时间:2023-12-04 03:16:18 26 4
gpt4 key购买 nike

前几天我在谈论函数式编程——尤其是 Haskell 和一些 Java/Scala 人,他们问我什么是 Monad,它们在哪里是必要的。

好吧,定义和例子并不难 - Maybe Monad , IO Monad , State Monad等等,所以每个人至少部分地同意我说 Monads 是件好事。

但是哪里需要 Monad - Maybe可以通过像 -1 这样的魔法值来避免在 Integer 的设置中, 或 ""String 的设置中.我写了一个没有 State 的游戏Monad,一点都不好,但初学者会这样做。

所以我的问题: Monads在哪里是必要的? ——而且根本无法避免。
(并且没有混淆 - 我喜欢 Monads 并使用它们,我只是想知道)。

编辑

我想我必须澄清一下我做 不是 认为使用“Magic Values”是一个很好的解决方案,但是很多程序员都在使用它们,尤其是在低级语言中,如 中号或者在 SHell 脚本中,通常通过返回 -1 来暗示错误。 .

我已经很清楚不使用 monads 不是一个好主意。抽象通常很有帮助,但也很复杂,因此很多人都在为 monad 的概念而苦恼。

我的问题的核心是是否可以这样做 IO ,没有单子(monad),仍然是纯粹的和功能性的。我知道将一个已知的好的解决方案搁置一旁,以及用打火石和火种而不是使用打火机生火,这将是乏味和痛苦的。

@Antal S-Z 引用的文章很棒you could have invented monads ,我略读了一遍,有时间一定会读的。更有启发性的答案隐藏在@Antal S-Z i remember the time before monads 引用的博客文章的评论中,这是我问这个问题时正在寻找的东西。

最佳答案

我认为你永远不需要单子(monad)。它们只是当您使用某些类型的功能时自然出现的一种模式。我见过的对这种观点的最好解释是 Dan Piponi (sigfpe) 的优秀博文 "You Could Have Invented Monads! (And Maybe You Already Have.)" ,这个答案的灵感来自。

你说你写了一个没有使用状态单子(monad)的游戏。它看起来像什么?您很有可能最终使用类型类似于 openChest :: Player -> Location -> (Item,Player) 的函数。 (打开一个箱子,可能会用陷阱伤害玩家,然后返回找到的元素)。一旦你需要组合这些,你可以手动完成( let (item,player') = openChest player loc ; (x,player'') = func2 player' y in ... )或重新实现状态单子(monad)的 >>=运算符(operator)。

或者假设我们正在使用带有哈希映射/关联数组的语言,而我们没有使用 monad。我们需要查找一些项目并使用它们;也许我们正试图在两个用户之间发送消息。

send username1 username2 = {
user1 = users[username1]
user2 = users[username2]
sendMessage user1 user2 messageBody
}

但是等等,这行不通; username1username2可能会丢失,在这种情况下,它们将是 nil-1或其他东西而不是所需的值。或者也许在关联数组中查找一个键会返回一个 Maybe a 类型的值。 ,所以这甚至会是一个类型错误。相反,我们必须写一些类似的东西
send username1 username2 = {
user1 = users[username1]
if (user1 == nil) return
user2 = users[username2]
if (user2 == nil) return
sendMessage user1 user2 messageBody
}

或者,使用 Maybe ,
send username1 username2 =
case users[username1] of
Just user1 -> case users[username2] of
Just user2 -> Just $ sendMessage user1 user2 messageBody
Nothing -> Nothing
Nothing -> Nothing

哎呀!这是困惑和过度嵌套的。所以我们定义了某种函数,它结合了可能失败的 Action 。也许像
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
f >>= Just x = f x
f >>= Nothing = Nothing

所以你可以写
send username1 username2 =
users[username1] >>= $ \user1 ->
users[username2] >>= $ \user2 ->
Just (sendMessage user1 user2 messageBody)

如果你真的不想用 Maybe ,那么你可以实现
f >>= x = if x == nil then nil else f x

同样的原则也适用。

不过,真的,我建议阅读 "You Could Have Invented Monads!"这是我对单子(monad)的直觉,并更好,更详细地解释它的地方。当处理某些类型时,Monads 会自然而然地出现。有时你把这个结构明确化,有时你没有,但仅仅因为你克制它并不意味着它不存在。从不需要使用特定结构的意义上说,您永远不需要使用 monad,但通常这是很自然的事情。并且认识到这里的通用模式,就像在许多其他事情中一样,可以让你编写一些很好的通用代码。

(另外,正如我使用的第二个示例所示,请注意,通过将 Maybe 替换为魔法值,您已经将婴儿与洗澡水一起扔了出去。仅仅因为 Maybe 是一个单子(monad)并不意味着您必须像这样使用它一;列表也是单子(monad),函数(形式为 r -> )也是单子(monad),但您不建议摆脱它们!:-))

关于language-agnostic - 单子(monad)——它们在哪里是必要的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12093638/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com