Monad“拆箱”

我按照教程Functors, Applicatives, And Monads In Pictures及其JavaScript version来提出问题 .

当文本说functor从上下文中解开值时,我理解发生了一个 Just 5 - > 5 转换 . 根据What does the "Just" syntax mean in Haskell?,只是 MaybeMaybe .

我的问题是整个展开的东西是如此神奇?我的意思是,有一些语言规则会自动解开"scoped"变量的问题是什么?在我看来,这个动作只是在某种表格中查找,其中符号 Just 5 对应于整数 5 .

我的问题受到JavaScript版本的启发,其中 Just 5 是原型数组实例 . 因此,实际上,解开根本不是火箭科学 .

这是"for-computation"类型的理由还是"for-programmer"?为什么我们在编程语言层面上区分 Just 55

回答(6)

2 years ago

首先,我不认为你可以理解Monads之类的东西而不理解类似Haskell的类型系统(即没有学习像Haskell这样的语言) . 是的,有许多教程声称不然,但我在学习Haskell之前已经阅读了很多这些教程,但我没有得到它 . 所以我的建议是:如果你想了解Monads至少学习一些Haskell .

对于您的问题“为什么我们在编程语言级别上区分 Just 55 ?” . 为了类型安全 . 在大多数不是Haskell的语言中, nilwhatever 通常用于表示缺少值 . 然而,这经常导致像 NullPointerExceptions 这样的事情,因为你没有预料到 Value 可能不存在 .

在Haskell中没有 null . 因此,如果您的类型为 Int 或其他任何值,则该值不能为 null . 你保证有 Value . 大!但有时你实际上想要/需要编码缺少值 . 在Haskell中,我们使用 Maybe . 所以 Maybe Int 类型的东西可以是 Just 5Nothing . 这种方式明确表示该值可能不存在,并且您不会意外忘记它可能是 Nothing 因为您必须显式解包该值 .

这与Monads没什么关系,除了 Maybe 恰好实现了Monad类型(如果你熟悉Java,类型类有点像Java接口) . 那也许主要不是Monad,但恰好也是Monad .

2 years ago

我想你是从错误的方向看这个 . Monad 明确不是关于展开的 . Monad 是关于作文 .

它允许您组合(不一定应用)类型为 a -> m b 的函数和类型为 m a 的值以获取类型 m b 的值 . 我可以理解你可能认为显而易见的方法是将类型 m a 的值展开为 a 类型的值 . 但很少有 Monad 实例以这种方式工作 . 实际上,唯一能够以这种方式工作的是与 Identity 类型相同的那些 . 对于几乎所有的 Monad 实例,都无法打开一个值 .

考虑 Maybe . 当起始值为 Nothing 时,将 Maybe a 类型的值展开为类型 a 的值是不可能的 . Monadic组合必须做一些比打开更有趣的事情 .

考虑 [] . 将 [a] 类型的值展开为类型为 a 的值是不可能的,除非输入恰好是长度为1的列表 . 在其他所有情况下,monadic组合正在做一些比解包更有趣的事情 .

考虑 IO . 像 getLine :: IO String 这样的值不包含 String 值 . 它包裹着什么东西 . IO 值的monadic组合不会解开任何东西 . 它将 IO 值组合成更复杂的 IO 值 .

我认为值得调整你对 Monad 意味着什么的看法 . 如果它只是一个展开的界面,那将是非常无用的 . 它's more subtle, though. It'是一个合成界面 .

2 years ago

一个可能的例子是:考虑Haskell类型 Maybe (Maybe Int) . 其值可以是以下形式

  • Nothing

  • Just Nothing

  • Just (Just n) 对于某个整数 n

没有 Just 包装器,我们无法区分前两个 .

实际上,可选类型 Maybe a 的重点是向现有类型 a 添加新值( Nothing ) . 为了确保 Nothing 确实是一个新值,我们将其他值包装在 Just 中 .

在类型推断期间它也有帮助 . 当我们看到函数调用 f 'a' 时,我们可以看到 f 在类型 Char 处被调用,而不是在类型 Maybe CharMaybe (Maybe Char) 处调用 . 类型类系统允许 f 在每种情况下都有不同的实现(这类似于某些OOP语言中的"overloading") .

2 years ago

"unwrap"的含义取决于容器 . Maybe 只是一个例子 . 当容器是 [] 而不是 Maybe 时,"Unwrapping"表示完全不同的东西 .

关于整个展开的东西的神奇之处在于抽象:在Monad中我们有一个“展开”的概念,它抽象出容器的本质;然后它开始变得“神奇”......

你问 Just 意味着什么:只是通过数据声明定义的Haskell中的数据类型构造函数,如:

data Maybe a = Just a | Nothing

Just 获取 a 类型的值并创建类型为 Maybe a 的值 . 它's Haskell'是一种从 Maybe a 类型的值中区分 a 类型的值的方法

2 years ago

我的问题是,整个展开的事情是多么神奇?

它没什么神奇之处 . 您可以使用花园式模式匹配(此处为 case 表达式的形状)来定义...

mapMaybe :: (a -> b) -> Maybe a -> Maybe b
mapMaybe f mx = case mx of
    Just x -> Just (f x)
    _ -> mx

... Maybefmap 完全相同 . Functor 类添加的唯一东西 - 它是一个非常有用的东西,毫无疑问 - 是一个额外的抽象级别,涵盖了可以映射的各种结构 .

为什么我们在编程语言水平上区分Just 5和5?

Just 55 之间的区别更有意义的是它们之间的区别 - 例如在 Maybe IntInt 之间 . 如果您有 x :: Int ,则可以确定 x 是您可以使用的 Int 值 . 但是,如果你有 mx :: Maybe Int ,则没有这样的确定性,因为 Int 可能会丢失(即 mx 可能是 Nothing ),并且类型系统会强制您确认并处理这种可能性 .

另请参阅:jpath's answer以进一步评论 Maybe 的有用性(它不一定与 FunctorMonad 等类相关联); Carl's answer有关 FunctorMonad (超出 Maybe 示例)等类的有用性的进一步评论 .

2 years ago

首先,您需要从问题中删除monad . 他们无所事事 . 将这篇文章视为monad的观点之一,也许它不适合你,在类型系统中你可能仍然很少理解会理解haskell中的monad .

所以,你的问题可以改为:为什么没有隐式转换 Just 5 => 5 ?但答案很简单 . 因为值 Just 5 的类型为 Maybe Integer ,所以这个值可能是 Nothing ,但在这种情况下必须做什么编译?只有程序员才能解决这种情况 .

但还有更令人不安的问题 . 有类型,例如 newtype Identity a = Identity a . 它只是包装一些 Value . 那么,为什么没有隐性转换 Identity a => a

简单的答案是 - 尝试实现这一点会导致不同的系统类型,这些系统类型不会具有当前存在的许多优良品质 . 据此,它可以牺牲其他可能性的利益 .