它实际上只是一个普通的数据构造函数,恰好在Prelude中定义,Prelude是自动导入每个模块的标准库。
结构上的可能是什么
定义看起来像这样:
data Maybe a = Just a
| Nothing
该声明定义了一个类型,Maybe a
它由一个类型变量参数化a
,这意味着您可以将它与任何类型一起使用来代替a
.
构造和破坏
该类型有两个构造函数,Just a
和Nothing
. 当一个类型有多个构造函数时,这意味着该类型的值必须只使用一个可能的构造函数来构造。对于这种类型,值是通过Just
或构造Nothing
的,没有其他(非错误)可能性。
由于Nothing
没有参数类型,因此当它用作构造函数时,它会命名一个常量值,该常量值是Maybe a
所有类型的类型成员a
。但是Just
构造函数确实有一个类型参数,这意味着当用作构造函数时,它就像一个从 typea
到的函数Maybe a
,即它具有类型a -> Maybe a
因此,一个类型的构造函数构建了该类型的值;事情的另一面是当你想使用那个值时,这就是模式匹配发挥作用的地方。与函数不同,构造函数可用于模式绑定表达式,这是您可以对属于具有多个构造函数的类型的值进行案例分析的方式。
为了Maybe a
在模式匹配中使用值,您需要为每个构造函数提供一个模式,如下所示:
case maybeVal of
Nothing -> "There is nothing!"
Just val -> "There is a value, and it is " ++ (show val)
在那个 case 表达式中,如果值是 ,则第一个模式将匹配Nothing
,如果值是用 构造的,则第二个模式将匹配Just
。如果第二个匹配,它还将名称绑定到在构造您匹配的值时val
传递给Just
构造函数的参数。
也许意味着什么
也许您已经熟悉它是如何工作的;值并没有真正的魔力Maybe
,它只是一个普通的 Haskell 代数数据类型 (ADT)。但是它被使用了很多,因为它有效地“提升”或扩展了一个类型,比如Integer
从你的例子中,到一个新的上下文中,在这个上下文中它有一个额外的值(Nothing
),代表缺乏价值!然后,类型系统要求您检查该额外值,然后它才能让您获得可能Integer
存在的值。这可以防止大量错误。
今天的许多语言通过 NULL 引用处理这种“无价值”值。Tony Hoare 是一位杰出的计算机科学家(他发明了快速排序并且是图灵奖得主),他承认这是他的“十亿美元的错误”。Maybe 类型不是解决这个问题的唯一方法,但它已被证明是一种有效的方法。
也许作为函子
将一种类型转换为另一种类型以便对旧类型的操作也可以转换为对新类型起作用的想法是 Haskell 类型类背后的概念,称为Functor
,它Maybe a
有一个有用的实例。
Functor
提供了一个名为 的方法fmap
,该方法将范围从基本类型(例如Integer
)的值的函数映射到范围来自提升类型的值的函数(例如Maybe Integer
)。转换fmap
为处理Maybe
值的函数的工作方式如下:
case maybeVal of
Nothing -> Nothing -- there is nothing, so just return Nothing
Just val -> Just (f val) -- there is a value, so apply the function to it
所以如果你有一个Maybe Integer
valuem_x
和一个Int -> Int
function f
,你可以直接fmap f m_x
将这个函数应用到 ,而不用担心它是否真的有一个值。事实上,您可以将整个提升函数链应用于值,并且只需要担心在完成后显式检查一次。f
Maybe Integer
Integer -> Integer
Maybe Integer
Nothing
也许作为一个单子
我不确定您对 a 的概念有多熟悉Monad
,但您至少以前使用IO a
过,并且类型签名IO a
看起来非常类似于Maybe a
. 尽管IO
它的特殊之处在于它不会向您公开其构造函数,因此只能由 Haskell 运行时系统“运行”,但它仍然是Functor
除了Monad
. 事实上,在一个重要的意义上,aMonad
只是一种Functor
具有一些额外功能的特殊类型,但这不是深入探讨的地方。
无论如何,Monads 喜欢IO
将类型映射到表示“产生值的计算”的新类型,并且您可以Monad
通过一个非常fmap
相似的函数 将函数提升为类型,该函数liftM
将常规函数转换为“计算结果,通过评估功能。”
你可能已经猜到(如果你已经读到这里的话)这Maybe
也是一个Monad
. 它表示“可能无法返回值的计算”。就像fmap
示例一样,这使您可以进行大量计算,而无需在每一步之后显式检查错误。事实上,Monad
实例的构造方式,一旦遇到 a就停止Maybe
对值的计算,所以它有点像计算中间的立即中止或无值返回。Nothing
你可以写也许
就像我之前说的,Maybe
语言语法或运行时系统中没有任何固有的类型。如果 Haskell 默认没有提供它,你可以自己提供它的所有功能!事实上,无论如何你都可以自己重新编写它,使用不同的名称,并获得相同的功能。
希望您Maybe
现在了解类型及其构造函数,但如果仍有任何不清楚的地方,请告诉我!