Haskell 单子;拆箱“;
我的问题是在学习教程及其内容时提出的 当文本说函子从上下文中展开值时,我知道正在发生一个Haskell 单子;拆箱“;,haskell,monads,functor,Haskell,Monads,Functor,我的问题是在学习教程及其内容时提出的 当文本说函子从上下文中展开值时,我知道正在发生一个仅5->5转换。根据,Just是Maybemonad的“定义范围” 我的问题是,整个拆开包装的事情有什么神奇之处?我的意思是,有一些自动打开“范围”变量的语言规则有什么问题?在我看来,此操作只是某种表中的查找,其中符号Just 5对应于整数5 我的问题来自JavaScript版本,其中只有5个是原型数组实例。因此,拆开包装确实根本不是火箭科学 这是“为了计算”的原因还是“为了程序员”的原因?为什么我们要在编程
仅5
->5
转换。根据,Just是Maybe
monad的“定义范围”
我的问题是,整个拆开包装的事情有什么神奇之处?我的意思是,有一些自动打开“范围”变量的语言规则有什么问题?在我看来,此操作只是某种表中的查找,其中符号Just 5
对应于整数5
我的问题来自JavaScript版本,其中只有5个是原型数组实例。因此,拆开包装确实根本不是火箭科学
这是“为了计算”的原因还是“为了程序员”的原因?为什么我们要在编程语言级别上区分只有5
和5
?什么是“展开”取决于容器<代码>也许
只是一个例子。当容器是[]
而不是时,“展开”意味着完全不同的东西
整个拆开包装的神奇之处在于抽象:在单子中,我们有一个“拆开包装”的概念,它抽象了容器的本质;然后它开始变得“神奇”
您会问Just是什么意思:Just只是Haskell中的一个数据类型构造函数,通过如下数据声明定义:
data Maybe a = Just a | Nothing
只需
获取类型为a
的值,然后创建类型为的值,可能是a
。这是哈斯凯尔区分类型a
的高值和类型的值的方法,也许a
首先,我认为如果不理解类似哈斯凯尔的类型系统(即不学习类似哈斯凯尔的语言),你就无法理解单子之类的东西。是的,有很多教程声称不是这样,但我在学习Haskell之前读了很多,但我没有理解。所以我的建议是:如果你想了解单子,至少要学一些哈斯克尔
对于您的问题“为什么我们要在编程语言级别上区分5
和5
?”。用于类型安全。在大多数恰好不是Haskell的语言中,null
,nil
,无论什么,都经常用来表示没有值。但是,这通常会导致出现诸如NullPointerExceptions
,因为您没有预料到可能不存在值
在Haskell中没有null
。因此,如果您有一个类型为Int
的值或任何其他值,则该值不能为null
。你被保证有一个价值。伟大的但有时您实际上想要/需要对缺少值的情况进行编码。在Haskell中,我们使用可能
。所以类型为的东西可能是Int
可以是只有5个或者什么都没有。通过这种方式,可以明确表示该值可能不在那里,并且您不能意外地忘记它可能是Nothing
,因为您必须显式地展开该值
这实际上与Monad无关,只是可能碰巧实现了Monad类型类(如果您熟悉Java,类型类有点像Java接口)。这可能不是主要是Monad,但恰好也是一个单元格。 < P>一个可能的例子是:考虑Haskell类型<代码>(也许INT)< /代码>。其值可以是以下形式
Nothing
什么都没有
Just(Just n)
对于某些整数n
如果没有包装器,我们就无法区分前两个
实际上,可选类型可能是a
的全部要点是向现有类型a
添加一个新值(Nothing
)。为了确保这样的Nothing
确实是一个新值,我们将其他值包装在Just
中
它也有助于类型推断。当我们看到函数调用f'a'
时,我们可以看到f
是在类型Char
处调用的,而不是在类型Maybe Char
或Maybe(Maybe Char)
处调用的。typeclass系统将允许f
在每种情况下都有不同的实现(这类似于某些OOP语言中的“重载”)我认为您从错误的方向看待这一点Monad
显然不是关于展开的<代码>单子
是关于合成的
它允许您将a->mb
类型的函数与ma
类型的值组合(不一定应用),以获得mb
类型的值。我可以理解您可能认为最明显的方法是将ma
类型的值展开为a
类型的值。但是很少有Monad
实例是这样工作的。事实上,只有那些与Identity
类型等效的类型才能以这种方式工作。对于几乎所有的Monad
,都不可能打开一个值
考虑一下可能
。当起始值为Nothing
时,不可能将类型的值a
展开为a
类型的值。一元构图必须做一些比拆开包装更有趣的事情
考虑[]
。除非输入恰好是长度为1的列表,否则无法将[a]
类型的值展开为a
类型的值。在其他任何情况下,一元构图都比拆开包装更有趣
考虑IO
。像getLine::IO String
这样的值不包含String
值。它显然是不可能打开的,因为它没有包装什么东西。
mapMaybe :: (a -> b) -> Maybe a -> Maybe b
mapMaybe f mx = case mx of
Just x -> Just (f x)
_ -> mx