我对上下文中的价值有一个小问题。
选择Just 'a'
,因此在这种情况下,Maybe
类型的上下文中的值为'a'
选择[3]
,因此在此案例中,[a]
类型的上下文中的值为3
如果您将[3]
这样的monad应用于此[3] >>= \x -> [x+3]
,则表示您为x
分配值3
。没关系。
但是现在,取[3,2]
,那么类型[a]
的上下文中的值是多少?这很奇怪,如果你像这样申请monad:
[3,4] >>= \x -> x+3
它得到了正确的答案[6,7]
,但实际上我们不明白在这种情况下 x 是什么。您可以回答,啊 x 是3然后是4,而 x 将函数提供2次,并以Monad
结束:concat (map f xs)
这样:
[3,4] >>= concat (map f x)
因此,在这种情况下,[3,4]
将分配给 x 。这意味着错误,因为[3,4]
不是一个值。 Monad
错了。
答案 0 :(得分:6)
我认为你的问题过于关注价值观。 monad是一个类型构造函数,因此不关心有多少和哪种类型的值,但仅上下文。
Maybe a
可以是a
,也可以不是。很容易,你正确地观察到了。
Either String a
要么是a
,要么是String
形式的某些信息(例如a
的计算失败的原因)。
最后,[a]
是一个未知数量的a
s(或根本没有),这可能是由于计算模糊,或者是一个给出多个结果(如二次方程)。 / p>
现在,对于(>>=)
的解释,知道monad的基本属性(如何由类别理论家定义)是有帮助的
join :: m (m a) -> m a.
与fmap
一起,(>>=)
可以用join
来编写。
join
的含义如下:上下文,再次置于相同的上下文中,仍然具有相同的结果行为(对于此monad)。
这对于Maybe (Maybe a)
非常明显:某些内容基本上可以是Just (Just x)
,Nothing
或Just Nothing
,它提供的信息与Nothing
相同。因此,您可以只使用Maybe (Maybe a)
而不是使用Maybe a
,而不会丢失任何信息。这就是join
的作用:它转换为“更容易”的背景。
[[a]]
在某种程度上更难,但并不多。您基本上有多个/模糊结果的多个/模糊结果。一个很好的例子是通过求解二次方程得到的四次多项式的根。你首先得到两个解决方案,每个解决方案中你可以找到另外两个解决方案,从而产生四个根源。
但重点是,如果你说的是含糊不清的模糊结果,或者只是模棱两可的结果,那都没关系。您可以始终使用“模糊”上下文,并使用join
转换多个级别。
以下是(>>=)
对列表的作用:它将模糊函数应用于模糊值:
squareRoots :: Complex -> [Complex]
fourthRoots num = squareRoots num >>= squareRoots
可以改写为
fourthRoots num = join $ squareRoots `fmap` (squareRoots num)
-- [1,-1,i,-i] <- [[1,-1],[i,-i]] <- [1,-1] <- 1
因为您所要做的就是找到每个可能值的所有可能结果。
这就是列出join
为concat
的原因,实际上
m >>= f == join (fmap f) m
必须持有任何monad。
可以对IO
给出类似的解释。带有副作用的计算(也可能有副作用(IO (IO a)
))本质上只是带有副作用的东西。
答案 1 :(得分:3)
你必须接受&#34; context&#34;相当广泛。
解释值列表的一种常用方法是它代表一个不确定的值,因此[3,4]代表一个三或四的值,但我们不知道哪个(也许我们只知道它和#39; x ^ 2 - 7x + 12 = 0)的解。
如果我们再对其应用f,我们知道它的6或7但我们仍然不知道哪个。
你不习惯的不确定值的另一个例子是3.它可能意味着3 :: Int或3 :: Integer甚至有时3.0 :: Double。感觉更容易,因为只有一个符号表示不确定的值,而在列表中,列出了所有可能性(!)。
如果你写
asum = do
x <- [10,20]
y <- [1,2]
return (x+y)
您将获得一个包含四个可能答案的列表:[11,12,21,22]
对于您可以添加x和y的每种可能方式,这是一个。
答案 2 :(得分:1)
这不是上下文中的值,而是类型。
Just 'a' :: Maybe Char
--- Char
位于Maybe
上下文中。
[3, 2] :: [Int]
--- Int
位于[]
上下文中。
a
中的m a
中是否有一个,没有一个或多个不在此点。
修改:考虑(>>=) :: Monad m => m a -> (a -> m b) -> m b
的类型。
您举例Just 3 >>= (\x->Just(4+x))
。但请考虑Nothing >>= (\x->Just(4+x))
。上下文中没有任何价值。但类型在上下文中都是一样的。
认为x
必然是单一价值是没有意义的。 x
只有一种类型。如果我们正在处理Identity
monad,那么x
将是单个值,是的。如果我们在Maybe
monad中,x
可能是单个值,或者它可能永远不会是值。如果我们在列表monad中,x
可能是单个值,或者根本不是值,或者是各种不同的值......但它不是所有这些不同值的列表。< / p>
你的另一个例子--- [2, 3] >>= (\x -> x + 3)
--- [2, 3]
不传递给该函数。 [2, 3] + 3
会出现类型错误。 2
传递给函数。 3
也是如此。该函数被调用两次,为这两个输入提供结果,结果由>>=
运算符组合。 [2, 3]
未传递给函数。
答案 3 :(得分:0)
“context”是我最喜欢考虑monad的方法之一。但是你有一点误解。
选择Just'a',因此在这种情况下,Maybe类型的上下文值为'a'
不完全。你继续说the value in context
,但在上下文中并不总是有一个值,或者如果存在,那么它不一定是唯一的值。这一切都取决于我们正在讨论的 上下文。
Maybe
上下文是“可空性”或潜在缺席的背景。可能有某些内容,或者可能有Nothing
。 Nothing
没有“内部”的价值。因此,可能的上下文可能内部有值,或者可能没有。如果我给你一个Maybe Foo
,那么你不能认为有一个Foo
。相反,您必须假设它在上下文中是Foo
,而实际上可能有Nothing
而不是。您可能会说类型为Maybe Foo
的内容属于可空Foo
。
取[3],因此在这种情况下类型[a]的上下文中的值是3
同样,不太对劲。列表表示 nondeterministic 上下文。我们不太确定应该是什么“价值”,或者根本就没有。在单例列表的情况下,例如[3]
,则是,只有一个。但是考虑列表[3,4]
的一种方法是某些不可观察的值,我们不确定它是什么,但我们确定它是3
或它是4
。您可能会说[Foo]
类型的内容属于非确定性Foo
。
[3,4] >>= \x -> x+3
这是一种类型错误;不太清楚你的意思。
因此,在这种情况下,
[3,4]
将被分配给x。这意味着错误,因为[3,4]
不是一个值。莫纳德错了。
你在这里完全失去了我。 Monad
的每个实例都有自己的>>=
实现,它定义了它所代表的上下文。对于列表,定义是
(xs >>= f) = (concat (map f xs))
您可能希望了解与Functor
的想法相关的Applicative
和Monad
操作,并可能有助于消除一些混淆。