Monad“拆箱”

时间:2016-11-27 15:27:15

标签: haskell monads functor

在关注教程Functors, Applicatives, And Monads In Pictures及其JavaScript version

后,我的问题出现了

当文本说仿函数从上下文中展开值时,我理解Just 5 - > 5转型正在发生。根据{{​​3}},Just在Maybe monad的“范围”中定义。

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

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

这是“计算”类型的理由还是“程序员”理由?为什么我们在编程语言级别上区分Just 55

6 个答案:

答案 0 :(得分:8)

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

问题"为什么我们在编程语言层面上区分mapJust 5?"。为了类型安全。在大多数不是Haskell 5nullnil的语言中,通常用于表示缺少值。然而,这经常导致像whatever这样的事情,因为你没有预料到价值可能不存在。

在Haskell中没有NullPointerExceptions。因此,如果您的值为null或其他任何值,则该值不能为Int。你保证有价值。大!但有时你实际上想要/需要编码缺少值。在Haskell中,我们使用null。因此Maybe类型的某些内容可以是Maybe IntJust 5。通过这种方式显然,值可能不存在,并且您不会意外忘记它可能是Nothing,因为您必须显式地解包该值。

这与Monads没有任何关系,除了Nothing碰巧实现了Monad类型类(如果你熟悉Java,类型类有点像Java接口)。那也许主要不是Monad,但恰好也是Monad。

答案 1 :(得分:5)

我认为你是从错误的方向看这个。 Monad明确关于展开。 Monad是关于作文的。

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

考虑Maybe。如果起始值为Maybe a,则无法将类型a的值展开为类型Nothing的值。 Monadic作品必须做一些比打包更有趣的事情。

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

考虑IO。像getLine :: IO String这样的值不包含String值。打开它几乎是不可能的,因为它没有包装东西。 IO值的monadic组合不会解开任何东西。它将IO值组合成更复杂的IO值。

我认为值得调整你对Monad意味着什么的看法。如果它只是一个展开的界面,那将毫无用处。但它更加微妙。这是一个作文界面。

答案 2 :(得分:4)

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

  • Nothing
  • Just Nothing
  • Just (Just n)表示某个整数n

如果没有Just包装,我们就无法区分前两个。

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

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

答案 3 :(得分:2)

什么"展开"意味着取决于容器。 Maybe只是一个例子。 "解缠"当容器为[]而不是Maybe时,表示完全不同的东西。

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

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

 data Maybe a = Just a | Nothing

Just获取a类型的值,并创建类型为Maybe a的值。 Haskell的方法是将a类型的值与Maybe a类型的值区分开来

答案 4 :(得分:2)

  

我的问题是,整个展开过程中有什么神奇之处?

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

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

...与fmap的{​​{1}}完全相同。 Maybe类唯一添加的东西 - 它是一个非常有用的东西,毫无疑问 - 是一个额外的抽象层次,它涵盖了可以映射的各种结构。

  

为什么我们在编程语言级别上区分FunctorJust 5

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

另请参阅:jpath's answer,以便进一步评论Nothing的有用性(不一定与MaybeFunctor等类相关联; Carl's answer有关MonadFunctor等类的有用性的进一步评论(Monad示例之外)。

答案 5 :(得分:1)

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

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

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

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