实际上,它只是在Prelude中定义的普通数据构造函数,Prelude是自动导入到每个模块的标准库。
结构上可能是什么
定义看起来像这样:
data Maybe a = Just a
| Nothing
该声明定义了一个类型,Maybe a
该类型由类型变量参数化a
,这仅意味着您可以将其用于任何类型来代替a
。
构造与破坏
该类型具有两个构造函数,Just a
和Nothing
。当一个类型具有多个构造函数时,这意味着该类型的值必须仅使用可能的构造函数之一进行构造。对于这种类型,值是通过Just
或构造的Nothing
,没有其他(非错误)可能性。
由于Nothing
没有参数类型,因此当它用作构造函数时,将命名一个常量值,该值是Maybe a
所有类型的类型成员a
。但是Just
构造函数确实具有类型参数,这意味着当用作构造函数时,它的行为就像从type a
到函数一样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)
在那种情况下,如果值是,则第一个模式将匹配,如果使用Nothing
构造值,则第二个模式将匹配Just
。如果第二个匹配,则还会val
在Just
构造要与之匹配的值时将名称绑定到传递给构造函数的参数。
可能是什么意思
也许您已经熟悉了它的工作方式。Maybe
值实际上没有任何魔术,它只是普通的Haskell代数数据类型(ADT)。但是它使用了很多,因为它可以有效地“提升”或扩展类型(例如,Integer
从您的示例中)到新的上下文中,在该上下文中,它具有Nothing
表示缺乏价值的额外值()!那么该类型的系统要求您检查额外的价值之前,它会让你在Integer
这可能是在那里。这样可以防止大量的错误。
今天,许多语言都通过NULL引用来处理这种“无值”值。著名的计算机科学家Tony Hoare(他发明了Quicksort,是图灵奖的获得者),将其归结为他的“十亿美元的错误”。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
值m_x
和一个Int -> Int
函数f
,则可以fmap f m_x
将函数f
直接应用于,Maybe Integer
而不必担心它是否真正有值。实际上,您可以将整个提升Integer -> Integer
函数链应用于Maybe Integer
值,而不必担心Nothing
在完成时显式检查一次。
也许是单子
我不确定您对a的概念是否熟悉Monad
,但是您至少已经使用IO a
过,而且类型签名IO a
看起来与十分相似Maybe a
。尽管IO
它的特殊之处在于它不会向您公开其构造函数,因此只能由Haskell运行时系统“运行”,但它还是a Functor
的补充Monad
。实际上,从某种意义上讲,a Monad
只是一种特殊的东西,Functor
具有一些额外的功能,但这并不是进入其中的地方。
无论如何,Monads会将IO
映射类型喜欢为表示“导致结果的计算”的新类型,您可以Monad
通过一个非常类似fmap
的函数将函数提升为类型,该函数 liftM
将常规函数转换为“通过计算求值而得到值的计算”功能。”
您可能已经猜到了(如果您已经读到了这本书),那Maybe
也是一个Monad
。它表示“可能无法返回值的计算”。就像fmap
示例一样,这使您可以进行大量计算,而不必在每个步骤之后都明确检查错误。实际上,Monad
实例的构造方式是,一旦遇到a,就停止对Maybe
值的计算,因此,这就像在计算过程中立即中止或无值返回。Nothing
你可能已经写过
就像我之前说过的那样,Maybe
语言语法或运行时系统中没有任何类型固有的东西。如果Haskell默认不提供它,则您可以自己提供其所有功能!实际上,您仍然可以自己重新编写它,使用不同的名称,并获得相同的功能。
希望您现在就了解了Maybe
类型及其构造函数,但是如果仍然不清楚,请告诉我!
Maybe
在其他语言会使用null
或使用的地方使用nil
((NullPointerException
在每个角落都潜伏着)。现在其他语言也开始使用此构造:Scala asOption
,甚至Java 8都具有该Optional
类型。