当前位置: 首页 > 知识库问答 >
问题:

为什么可能只包括?

轩辕风华
2023-03-14

由于这里有一些很好的答案,我基本上(显然是以有限的方式)理解了Haskell的Maybe的目的,并且它的定义是

data Maybe a = Nothing | Just a

然而,我不太清楚为什么Just是这个定义的一部分。据我所知,这就是Just本身的定义所在,但相关的留档并没有对此做太多说明。

我认为在的定义中使用的主要好处可能是,而不是简单地

data Maybe a = Nothing | a

它允许模式匹配到Just,并提供有用的功能,如isJustfromJust

为什么也许以前一种方式定义而不是后者?


共有3个答案

童华池
2023-03-14

Just是一个构造函数,a单独就属于a类型,而Just a构造了另一个类型可能是a

陆和泰
2023-03-14

另一种看待它的方式(除了Tikhon的答案之外)是考虑另一种基本的Haskell类型,other,其定义如下:

-- | A value that contains either an @a@ (the 'Left') constructor) or 
-- a @b@ (the 'Right' constructor).
data Either a b = Left a | Right b

这允许您拥有如下值:

example1, example2 :: Either String Int
example1 = Left "Hello!"
example2 = Right 42

...但也像这样:

example3, example4 :: Either String String
example3 = Left "Hello!"
example4 = Right "Hello!"

第一次遇到的类型是String,听起来像“要么是String,要么是String,”因此,你可能会认为它与String是一样的。但事实并非如此,因为Haskell联合是带标签的联合,因此任一字符串不仅记录了字符串,还记录了使用哪个“标记”(数据构造函数;在本例中是)来构造它。因此,即使两个备选方案都携带一个字符串作为有效载荷,您也能够知道任何一个值最初是如何构建的。这很好,因为在很多情况下,备选方案都是相同的类型,但构造函数/标记赋予了额外的含义:

data ResultMessage = FailureMessage String | SuccessMessage String

这里的数据构造器是FailureMessageSuccessMessage,您可以从名称中猜到,尽管这两种情况下的有效负载都是字符串,但它们的含义却截然不同!

所以把它带回也许/只是,这里发生的事情是Haskell就是这样统一工作的:联合类型的每个替代方案都有一个不同的数据构造函数,必须始终用于构造和模式匹配其类型的值。即使一开始您可能认为可以从上下文中猜测它,但它就是不这样做。

还有其他原因,更具技术性。首先,惰性评估的规则是根据数据构造函数定义的。简短的版本:惰性评估意味着如果Haskell被迫窥视类型的值内部,也许是,它将尝试执行所需的最低工作量,以确定它看起来像还是像Just x-最好它不会在执行此操作时窥视x内部。

第二:语言需要能够区分也许是也许(也许是a)也许(也许(也许是a))等类型。如果你考虑一下,如果我们有一个像你写的那样工作的类型定义:

data Maybe a = Nothing | a  -- NOT VALID HASKELL

...我们想制作一个类型为Maybe(Maybe a)的值,你无法区分这两个值:

example5, example6 :: Maybe (Maybe a)
example5 = Nothing
example6 = Just Nothing

乍一看,这可能有点傻,但假设您有一个值为“null”的映射:

-- Map of persons to their favorite number.  If we know that some person
-- doesn't have a favorite number, we store `Nothing` as the value for
-- that person.
favoriteNumber :: Map Person (Maybe Int)

...想要查找一个条目:

Map.lookup :: Ord k => Map k v -> k -> Maybe v

所以如果我们在地图上查找Mary,我们有:

Map.lookup favoriteNumber mary :: Maybe (Maybe Int)

现在结果意味着玛丽不在地图上,而只是无意味着玛丽在地图上,但她没有最喜欢的号码。

通迪
2023-03-14

Haskell的代数数据类型被标记为并集。按照设计,当您将两个不同的类型组合成另一个类型时,它们必须有构造函数来消除歧义。

数据类型与代数定义不匹配。

data Maybe a = Nothing | a

这里没有a的“标签”。在你的情况下,我们如何区分正常的、未包装的a

可能有一个构造函数,因为它必须设计一个构造函数。

其他语言确实有联合类型,可以像你想象的那样工作,但它们不适合Haskell。它们在实践中的表现不同,而且往往有点容易出错。

与普通的联合类型相比,更倾向于使用标记的联合有一些强大的设计原因。他们擅长类型推断。实际代码中的联合通常都有一个标签。而且,从优雅的角度来看,标记的并集自然适合这种语言,因为它们是产品(即元组和记录)的对偶。如果你好奇的话,我在一篇介绍和激励代数数据类型的博客文章中写到了这一点。

脚注

我在两个地方使用了联合类型:TypeScript和C。TypeScript编译为动态类型的JavaScript,这意味着它在运行时跟踪值的类型,基本上是一个标记。

C没有,但在实践中,大约90%的联合类型的使用要么有标记,要么有效地模拟结构子类型。我的一位教授实际上做了一项实证研究,研究了在真正的C代码中如何使用并集,但我不记得这是一篇什么论文。

 类似资料:
  • 问题内容: 我知道该包是由我们编写的每个Java程序自动导入的,因此包中的所有类对我们都是自动可用的。 我的问题是为什么也不要自动导入和其他软件包?那肯定会节省一些打字:) 因此,请解释为什么不这样做。 问题答案: 不自动导入过多的一个好理由是避免名称空间冲突。例如,如果其中的所有内容都是自动导入的,那么您想引用另一个名为“ Map”的类,则必须使用其完全限定的名称来引用它。 响应于该线程中的其他

  • 本文向大家介绍为什么HTML5只需要写就可以?相关面试题,主要包含被问及为什么HTML5只需要写就可以?时的应答技巧和注意事项,需要的朋友参考一下 HTML5 之前基于 SGML, SGML 需要指定 DTD 解析文档, 可通过<!DOCTYPE>指定要使用的 DTD, 若不写则会进入怪异模式; HTML5 不基于 SGML, 不需要指明 DTD, 其<!DOCTYPE>只有一种: .

  • 问题内容: 这是我的代码: 问题答案: 像所有的专用方法(用“魔法姓名”开始和结束),是 不是 意味着要直接调用(除非是非常特殊的情况下,诸如最多=调用父类):确切地说,这种方法被称为的一部分内置程序和运算符的操作。在的情况下,所讨论的运算符是“包含检查”运算符。 在展示您的班级时(除了修正您的错字,并使用!!代替),并将其作为实例打印-以及对其他任何包含检查的打印,因为总会返回(因为,非空值字符

  • 在这里你可以下载一个acroform字段的pdf,他的大小正好是427KB 如果我删除这个唯一的字段,文件只有3KB,为什么会发生这种情况?我试着用PDF调试器分析,对我来说没有什么奇怪的。

  • 问题内容: 如果一个元组是不可变的,那么为什么它可以包含可变项呢? 似乎矛盾的是,当可变项(例如列表)确实被修改时,它所属的元组保持不变。 问题答案: 这是一个很好的问题。 关键的见解是,元组无法知道其中的对象是否可变。使对象可变的唯一方法是拥有一种更改其数据的方法。通常,无法检测到此情况。 另一个见解是Python的容器实际上不包含任何东西。相反,它们保留对其他对象的引用。同样,Python的变

  • 问题内容: 苹果的新框架似乎使用了一种 新型语法 ,可以有效地构建元组,但又具有另一种语法: 尝试解决这种语法的实际含义时 ,我发现这里使用的初始化程序将类型的闭包 作为第二个参数,其中的通用参数是通过闭包推断的。为了找出要推断的类型,我对代码进行了一些更改,并保持其功能: 以此,表明自己是类型,即类型。向上看,我发现它是一个源自自身的包装器类型,只能通过传递应该包装的元组来进行初始化。 题 现在