我按照教程Functors, Applicatives, And Monads In Pictures及其JavaScript version来提出问题 .
当文本说functor从上下文中解开值时,我理解发生了一个 Just 5
- > 5
转换 . 根据What does the "Just" syntax mean in Haskell?,只是 Maybe
的 Maybe
.
我的问题是整个展开的东西是如此神奇?我的意思是,有一些语言规则会自动解开"scoped"变量的问题是什么?在我看来,这个动作只是在某种表格中查找,其中符号 Just 5
对应于整数 5
.
我的问题受到JavaScript版本的启发,其中 Just 5
是原型数组实例 . 因此,实际上,解开根本不是火箭科学 .
这是"for-computation"类型的理由还是"for-programmer"?为什么我们在编程语言层面上区分 Just 5
和 5
?
6 回答
首先,我不认为你可以理解Monads之类的东西而不理解类似Haskell的类型系统(即没有学习像Haskell这样的语言) . 是的,有许多教程声称不然,但我在学习Haskell之前已经阅读了很多这些教程,但我没有得到它 . 所以我的建议是:如果你想了解Monads至少学习一些Haskell .
对于您的问题“为什么我们在编程语言级别上区分
Just 5
与5
?” . 为了类型安全 . 在大多数不是Haskell的语言中,nil
,whatever
通常用于表示缺少值 . 然而,这经常导致像NullPointerExceptions
这样的事情,因为你没有预料到 Value 可能不存在 .在Haskell中没有
null
. 因此,如果您的类型为Int
或其他任何值,则该值不能为null
. 你保证有 Value . 大!但有时你实际上想要/需要编码缺少值 . 在Haskell中,我们使用Maybe
. 所以Maybe Int
类型的东西可以是Just 5
或Nothing
. 这种方式明确表示该值可能不存在,并且您不会意外忘记它可能是Nothing
因为您必须显式解包该值 .这与Monads没什么关系,除了
Maybe
恰好实现了Monad类型(如果你熟悉Java,类型类有点像Java接口) . 那也许主要不是Monad,但恰好也是Monad .我想你是从错误的方向看这个 .
Monad
明确不是关于展开的 .Monad
是关于作文 .它允许您组合(不一定应用)类型为
a -> m b
的函数和类型为m a
的值以获取类型m b
的值 . 我可以理解你可能认为显而易见的方法是将类型m a
的值展开为a
类型的值 . 但很少有Monad
实例以这种方式工作 . 实际上,唯一能够以这种方式工作的是与Identity
类型相同的那些 . 对于几乎所有的Monad
实例,都无法打开一个值 .考虑
Maybe
. 当起始值为Nothing
时,将Maybe a
类型的值展开为类型a
的值是不可能的 . Monadic组合必须做一些比打开更有趣的事情 .考虑
[]
. 将[a]
类型的值展开为类型为a
的值是不可能的,除非输入恰好是长度为1的列表 . 在其他所有情况下,monadic组合正在做一些比解包更有趣的事情 .考虑
IO
. 像getLine :: IO String
这样的值不包含String
值 . 它包裹着什么东西 .IO
值的monadic组合不会解开任何东西 . 它将IO
值组合成更复杂的IO
值 .我认为值得调整你对
Monad
意味着什么的看法 . 如果它只是一个展开的界面,那将是非常无用的 . 它's more subtle, though. It'是一个合成界面 .一个可能的例子是:考虑Haskell类型
Maybe (Maybe Int)
. 其值可以是以下形式Nothing
Just Nothing
Just (Just n)
对于某个整数n
没有
Just
包装器,我们无法区分前两个 .实际上,可选类型
Maybe a
的重点是向现有类型a
添加新值(Nothing
) . 为了确保Nothing
确实是一个新值,我们将其他值包装在Just
中 .在类型推断期间它也有帮助 . 当我们看到函数调用
f 'a'
时,我们可以看到f
在类型Char
处被调用,而不是在类型Maybe Char
或Maybe (Maybe Char)
处调用 . 类型类系统允许f
在每种情况下都有不同的实现(这类似于某些OOP语言中的"overloading") ."unwrap"的含义取决于容器 .
Maybe
只是一个例子 . 当容器是[]
而不是Maybe
时,"Unwrapping"表示完全不同的东西 .关于整个展开的东西的神奇之处在于抽象:在Monad中我们有一个“展开”的概念,它抽象出容器的本质;然后它开始变得“神奇”......
你问
Just
意味着什么:只是通过数据声明定义的Haskell中的数据类型构造函数,如:Just
获取a
类型的值并创建类型为Maybe a
的值 . 它's Haskell'是一种从Maybe a
类型的值中区分a
类型的值的方法它没什么神奇之处 . 您可以使用花园式模式匹配(此处为
case
表达式的形状)来定义......
Maybe
与fmap
完全相同 .Functor
类添加的唯一东西 - 它是一个非常有用的东西,毫无疑问 - 是一个额外的抽象级别,涵盖了可以映射的各种结构 .比
Just 5
和5
之间的区别更有意义的是它们之间的区别 - 例如在Maybe Int
和Int
之间 . 如果您有x :: Int
,则可以确定x
是您可以使用的Int
值 . 但是,如果你有mx :: Maybe Int
,则没有这样的确定性,因为Int
可能会丢失(即mx
可能是Nothing
),并且类型系统会强制您确认并处理这种可能性 .另请参阅:jpath's answer以进一步评论
Maybe
的有用性(它不一定与Functor
和Monad
等类相关联); Carl's answer有关Functor
和Monad
(超出Maybe
示例)等类的有用性的进一步评论 .首先,您需要从问题中删除monad . 他们无所事事 . 将这篇文章视为monad的观点之一,也许它不适合你,在类型系统中你可能仍然很少理解会理解haskell中的monad .
所以,你的问题可以改为:为什么没有隐式转换
Just 5 => 5
?但答案很简单 . 因为值Just 5
的类型为Maybe Integer
,所以这个值可能是Nothing
,但在这种情况下必须做什么编译?只有程序员才能解决这种情况 .但还有更令人不安的问题 . 有类型,例如
newtype Identity a = Identity a
. 它只是包装一些 Value . 那么,为什么没有隐性转换Identity a => a
?简单的答案是 - 尝试实现这一点会导致不同的系统类型,这些系统类型不会具有当前存在的许多优良品质 . 据此,它可以牺牲其他可能性的利益 .