pku*_*rov 4 monads haskell list monad-transformers
我只是完全混淆列表和monad,所以也许我的问题不正确或非常幼稚.我见过使用mapM_ FUNC做到这一点的方式在这里:
mapM_ print [1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)
但我不确切知道它是如何工作的,并想知道如何以这样的方式做到这一点:
x <- [1, 2, 3]
print x
Run Code Online (Sandbox Code Playgroud)
或者,如果我理解正确的话:
[1, 2, 3] >>= print
Run Code Online (Sandbox Code Playgroud)
我知道[1,2,3]有类型[a]和打印类型Show a => a -> IO ().另外我理解,对于使用monad List,我们需要List a在左边键入a -> List b,在右边键入func .我对吗?你能帮帮我吗?
UPD.感谢@MathematicalOrchid解释mapM_如何工作.从我的角度来说,我想解释一下,真正的问题不是在不同的行中打印任何结果,而是以monad List提供的方式做一些monadic动作(因为现在我正在处理OpenGL的东西).但我得知误解的根源在于混合单子.
UPD2.谢谢大家的回答.我为这种模糊的问题道歉.我不知道我需要什么答案,问题是什么.这是因为我不了解一些基础知识.因此,现在很难选择"正确的答案",因为每个答案都有我想要的平静.我决定选择最接近的(虽然现在不是最有用的)我想要的东西.
Mat*_*hid 12
你似乎在这里混淆了几件事.(特别是,列表形成一个monad,I/O形成一个不同的monad.)我会尝试清除它...
首先,该print函数将任何可显示的内容写入标准输出,然后是换行符.所以print [1, 2, 3]工作得很好,但显然在同一条线上写下所有内容.要在单独的行上写东西,我们需要print为每个项目单独调用.到现在为止还挺好.
该map函数将函数应用于列表的每个元素.因此map print [1, 2, 3]将适用print于列表中的每个项目.但是,结果是I/O操作列表.这不是我们所追求的.我们想要执行这些操作,而不是列出它们.
这样做的方法是使用>>操作符,它将两个I/O操作链接在一起(假设您对其结果不感兴趣 - 并且打印某些内容不会返回任何有趣的内容).因此,foldr (>>) (return ())将采用您的I/O操作列表并将其转换为单个I/O操作.事实上这个功能已经定义了; 它被称为sequence.
但是,map+ sequence是这样一种常见的组合,这也是已经定义的; 它被称为mapM_.(mapM如果你想保留结果,也可以没有下划线.但是打印不会返回任何内容,所以没有必要.)
现在,这就是为什么mapM_有效.现在你问为什么其他几种方法不起作用......
x <- [1, 2, 3]
print x
Run Code Online (Sandbox Code Playgroud)
这根本不起作用.第一行是monad列表.但第二行是在I/O monad中.你不能这样做.(你会得到一个相当莫名其妙的类型检查错误.)我应该指出这是Haskell所谓的"do-notation",上面的片段需要do前面的关键字才能真正成为有效的语法:
do
x <- [1, 2, 3]
print x
Run Code Online (Sandbox Code Playgroud)
无论哪种方式,它仍然无法正常工作.它几乎可以做什么map print [1, 2, 3],但不完全.(正如我所说,它不会进行类型检查.)
您还建议[1, 2, 3] >>= print,这与前面的代码段相同.(事实上,编译器将前者转换为后者.)原始版本不进行类型检查,并且由于同样的原因,这也不进行类型检查.
这有点像尝试在矩阵中添加数字.数字是可添加的东西.Matricies是可添加的东西.但你不能将一个添加到另一个,因为它们不一样.如果这是有道理的.
你想要的东西不能以这种方式工作,因为你试图将两个monad混合在一起:
do x <- [1,2,3]
print x
Run Code Online (Sandbox Code Playgroud)
具体来说,你是混合IO和[]monad.在do-notation中,所有语句都应该具有m a某些Monad 的类型m.但是在上面的代码中,第一个语句具有类型,[Integer]而第二个语句具有类型IO ().
要获得您想要的效果,您应该使用ListTmonad变换器.Monad变换器允许在堆叠中以特定顺序将monad混合在一起并根据需要组合它们的效果.
import Control.Monad.Trans
import Control.Monad.Trans.List
value = do x <- ListT (return [1,2,3])
lift (print x)
Run Code Online (Sandbox Code Playgroud)
这将返回一个类型的值ListT IO Integer.要从IO这个变换器中计算出来,请使用runListT.这将返回一个类型的值IO [Integer].这将输出:
GHCI> runListT value
1
2
3
[(),(),()]
Run Code Online (Sandbox Code Playgroud)
这相当于mapM print [1,2,3].扔掉的列表,并获得的效果mapM_ print [1,2,3],你可以使用void从Control.Monad.
GHCI> void . runListT $ value
1
2
3
Run Code Online (Sandbox Code Playgroud)
您可以使用按顺序sequence_执行IO操作:
sequence_ $ [1, 2, 3] >>= (\x -> [print x])
Run Code Online (Sandbox Code Playgroud)
但我认为mapM_相当清楚.
| 归档时间: |
|
| 查看次数: |
2797 次 |
| 最近记录: |