在Idris中,Maybe
类型定义如下:
data Maybe a = Just a | Nothing
它在Haskell中的定义类似:
data Maybe a = Just a | Nothing
deriving (Eq, Ord)
这是ML版本:
datatype 'a option = NONE | SOME of 'a
使用Just
和Some
有什么好处?
没有它们为什么不定义类型?
示例:
data Maybe a = a | Nothing
答案 0 :(得分:25)
之间会有什么区别
Maybe a
和
Maybe (Maybe a)
Nothing
和Just Nothing
之间应该存在差异。
答案 1 :(得分:10)
允许任何值为null
("十亿美元的错误")的关键问题是接收类型T
的值的接口无法声明是否可以处理null
,并且提供一个的接口无法声明它们是否可以生成null
。这意味着T
基本上可以使用的所有操作可能无效"当你传递T
时,这是一个相当大的漏洞,在所有由编译时类型检查提供的保证中。
对此的可能/可选解决方案是,T
类型不包含 null
值(从一开始就有这种语言,&# 39; s literal;在以后采用Optional类型而不删除对null
的支持的语言中,那只是一个需要约束的约定)。所以现在所有类型都表示接受T
的操作应该工作,当我传递T
时,无论我在哪里获得T
(如果你没有设法设法使非法国家无法代表"那么当然还有其他原因导致对象处于无效状态并导致失败,但至少在你通过{时{1}}实际上 。
有时我们确实需要一个可以是T
或者没有"的值。它毕竟是这样的普遍的情况,普遍的T
似乎是一个好主意。输入null
类型。但是为了避免重新陷入完全相同的旧陷阱,我得到一个可能为空的Maybe T
值并将其传递给无法处理T
的值,我们需要 none null
上的操作可直接用于T
。尝试这样做会导致类型错误,这是练习的全部要点。因此,我的Maybe T
值不能直接成为T
的成员;我需要将它们包含在里面一个Maybe T
中,这样如果我有一个Maybe T
,我就不得不编写处理两者的代码案例(仅在实际拥有Maybe T
的情况下才能调用适用于T
的操作。)
是否会在源代码中出现T
或Just
之类的单词,以及这是否实际上是通过内存中的附加装箱/间接实现的(某些语言确实代表{{1作为内部Some
的可空指针,所有这些都是无关紧要的。但Maybe T
案例必须与仅具有T
值不同。
答案 2 :(得分:7)
我不确定在这种情况下谈论“好处”是否正确。你在这里所拥有的只是在Haskell和ML中实现类型的方式的结果 - 基本上是Hindley-Milner代数类型系统。这种类型的系统基本上假定每个值都属于单类型(放弃Haskell的数字塔和底部,这不在本讨论中。)换句话说,没有子类型,这是有原因的 - 否则类型推断将是不可判定的。
当你定义类型Maybe a
时,你想要的是 adjoin 一个附加值a
表示的类型。但是你不能直接这样做 - 如果可以,那么a
的每个值都属于两种不同的类型 - 原始a
和Maybe a
。相反,所做的是a
嵌入在一个新类型中 - 你有一个规范注入a -> Just a
。换句话说,Maybe a
与a
和Nothing
的联合同构,您无法直接在HM类型系统中表示。
所以我不认为这种区分有益的论点是有效的 - 你不能拥有一个没有它的系统,它仍然是ML或Haskell或任何熟悉的基于HM的系统。
答案 3 :(得分:1)
问题在于,如果Maybe
按照您提议的方式定义,即data Maybe a = a | Nothing
,则无法区分a
值与Maybe a
值(和{{} 1}}就此而言)。
所以你可能会问,为什么我们需要有这样的区别?有什么好处?为了给你一个具体的例子,假设我们有一个带有Maybe (Maybe a)
列的SQL表。我们用haskell中的integer NOT NULL
表示。现在,如果我们稍后通过删除Int
约束来更改数据库模式以使列成为可选,那么我们必须将列的haskell表示更改为NOT NULL
。 Maybe Int
和Int
之间的明显区别将使重构我们的haskell代码以解释新模式变得非常容易。编译器会抱怨诸如从db中提取值并将其视为Maybe Int
(它可能不是整数,可能是Int
)。
答案 4 :(得分:0)
构造函数(Just
或Some
)的好处是它提供了一种区分数据类型分支的方法。也就是说,它避免了歧义。
例如,如果我们依赖于类型推断,那么下面的x类型看起来相当简单 - String
。
x = "Hello"
但是,如果我们允许您定义Maybe
,我们如何知道x
是String
,Maybe String
还是Maybe (Maybe String)
等。< / p>
还要考虑具有两种以上情况的数据类型:
data Tree a
= Empty
| Node (Tree a) (Tree a)
| Leaf a
如果我们只是删除了构造函数(Empty
除外),请按照Maybe
的建议,我们最终得到:
data Tree a
= Empty
| (Tree a) (Tree a)
| a
我希望你能看到歧义变得更加糟糕。
答案 5 :(得分:0)
在C ++ / Java'ish伪代码中考虑这个有些等同于...
template<class T>
abstract class Maybe<T> { ... }
template<class T>
class Just<T> : Maybe<T> {
// constructor
Just<T> (T val) { ... }
...
}
template<class T>
class Nothing<T> : Maybe<T> {
// constructor
Nothing () { ... }
...
}
这不是特定于Maybe,它可以应用于任何ADT。现在究竟会是什么
data Maybe a = a | Nothing
模特成? (假设它的法律语法)。
如果你要写一个switch语句,对模式进行'模式匹配',你将匹配什么(开关在TYPE上而不是值),类似这样的东西(不一定是有效的代码):
switch (typeof (x)) {
case Just<a> : ...
case Nothing<a> : ...
default : ... // Here you dont have any 'a' to get the inner type
}