关于上下文中的值(在Monad中应用)

时间:2012-11-23 15:35:32

标签: haskell

我对上下文中的价值有一个小问题。

  • 选择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错了。

4 个答案:

答案 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)NothingJust 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

因为您所要做的就是找到每个可能值的所有可能结果。

这就是列出joinconcat的原因,实际上

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上下文是“可空性”或潜在缺席的背景。可能有某些内容,或者可能有NothingNothing没有“内部”的价值。因此,可能的上下文可能内部有值,或者可能没有。如果我给你一个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的想法相关的ApplicativeMonad操作,并可能有助于消除一些混淆。