我是haskell的新手,我正在通过LearnYouAHaskell学习。我无法理解(>>)
运算符背后的原因。
默认实现是:
(>>) :: (Monad m) => m a -> m b -> m b
m >> n = m >>= \_ -> n
这是(据我所知)忽略第一个值并返回第二个值。但是,从LearnYouAHaskell的例子中可以看出:
ghci的>什么>>只是3
没有
ghci中>只是3>>没有
没有
所以它不忽略第一个值。然而,通过一些研究,我发现了here
的引用>>函数绑定运算符忽略其第一个操作的值 并且仅作为整体结果返回其第二个动作的结果。
所以我困惑关于此运算符的使用情况,我想问两件事:
答案 0 :(得分:15)
>>
函数只会忽略第一个值的结果,但不会忽略第一个值的副作用。要了解您的示例,请参阅如何定义Maybe
Monad:
instance Monad Maybe where
return = Just
(Just x) >>= f = f x
Nothing >>= _ = Nothing
>>
函数的定义如下:
m >> k = m >>= \_ -> k
根据{{1}} monad的定义, Nothing >> _
将生成Nothing
。在第二个示例中,Maybe
扩展为Just 3 >> Nothing
并生成Just 3 >>= \_ -> Nothing
。为了举例说明它如何忽略第一个动作的值但不忽略副作用,请考虑以下示例:
Nothing
你可以在上面的例子中看到,虽然它忽略了λ> print 3 >> print 4
3
4
print 3
的结果,但它没有忽略它的副作用,即显示{{1}到屏幕。
()
函数就会变得有用。偶尔使用它们的两个地方是处理Parsers(parsec,attoparsec)和Pipes库。
答案 1 :(得分:8)
它忽略了第一个动作的值,而不是动作本身。
Just 3 >> Just 5
操作Just 3
的值为3
。它在\_ -> n
部分被忽略。总体结果为Just 5
。
Just 3 >> Nothing
操作Just 3
的值为3
。它在\_ -> n
部分被忽略。总体结果为Nothing
。
Nothing >> Just 3
行动Nothing
根本不会产生任何价值。那么它传递给>>=
(或>>
)的右操作数是什么?它没有!构建>>=
monad的Maybe
,如果左侧操作为Nothing
,则根本不执行正确的操作,整体结果为Nothing
。
答案 2 :(得分:7)
要完成Sibi答案>>
可以被视为其他语言中的;
,如C或C ++ ..
当您使用C语言(或其他语言的同等语言)时
的printf("富&#34); 的printf("杆&#34);
你显然打印foobar
(副作用),但对printf
的调用也有一个返回值,在我们的例子中是打印的长度,即3 3.你有没有想过会发生什么这些数字?
他们被抛弃了,因为在C中, expr 1; exp 2 ,表示
(那时,你可以问你为什么编译器为了放弃它的结果而无法评估 expr1 ?由于副作用。在{{1的情况下副作用是打印一些东西。你很少对返回的值本身感兴趣。)
所以printf
可以看作是一个运算符,它采用2表达式并返回一个新表达式。这与;
运算符完全相同。
写作时
>>
它完全等同于 print "foo" >> print "bar"
,除了(并且主要区别)printf("foo");printf("bar")
不像C. >>
中的;
那样神奇。>>
它是用户定义的运算符,可以为每种类型的Monad重新定义。
这就是为什么Haskell程序员非常喜欢Monad的原因:简而言之,它允许你重新定义自己;
的行为。
正如我们所见,在C ;
中只评估一个表达式并丢弃它的值。事实上,它有点复杂,因为它不是break
或return
。 Maybe monad中的Nothing可以被视为break
或return
。 >>
评估第一个表达式,如果它是Nothing
则停止。否则它会丢弃它的值并继续。
您可以在C
中看到您的第一个示例(我认为它是有效的C)
3; return
和
return; 3
第一个例子,计算3
,丢弃其值并返回。
第二个,直接回来。
回答问题when is it usefull
?几乎所有的时候你使用IO,即使你很少看到它。
而不是写
print "foo" >> print "bar"
Haskell提供了一种语法糖,它通过do-notation将(几乎)新行转换为>>
,
所以你要写
do
print "foo"
print "bar"
严格等同于前一个版本(事实上,编号符号版本由编译器转换为前一版本。)
它甚至也相当于(即使很少使用)
do print "foo"; print "bar"
总结一下,>>
可以看作是;
的等价物,或换行符是其他语言,区别在于它的确切含义取决于上下文 (莫纳德正在采取行动)。
Maybe monad中的>>
与IO Monad中的>>
不同。
答案 3 :(得分:3)
首先让我们清楚你对Maybe
monad的困惑。请考虑以下
instance Monad Maybe where
return = Just
(Just x) >>= g = g x
Nothing >>= _ = Nothing
正如您所看到的,Nothing >>= _
是Nothing
。由于>>
只是>>=
的特殊情况,其中参数被忽略,结果是相同的。
这是因为Maybe
通常用于表示可能失败的计算。这是告诉我们“一旦你失败,你总是失败”。
现在回答你的问题。
putStrLn
的结果是()
,这既不重要也不会有任何用处。答案 4 :(得分:0)
原因很简单:单词实现需要两个操作:
>>=
>>
第一个执行操作并将其操作结果传递给另一个操作。例如:
Prelude> :t getLine
getLine :: IO String
Prelude> :t putStrLn
putStrLn :: String -> IO ()
两个函数:first getLine
只返回用IO
包装的String,它从stdin
读取字符串并将其包装到IO。第二个putStrLn
获取String
并打印出来。绑定有以下类型:
:t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
它可以表示为IO String -> (String -> IO String) -> IO String
,因此您可以通过执行getLine
将这两个或多个函数与(>> =)合并,并将结果String
传递给{{ 1}}:
putStrLn
因此,您可以在一个操作中组合这两个或更多功能。
第二个getLine >>= putStrLn
产生的几乎相同,但不需要先前的操作。
>>
它只是执行,第一个动作,而不是第二个动作,第一个动作的结果不需要第二个动作:
:t (>>)
(>>) :: Monad m => m a -> m b -> m b