了解何时使用let和&lt ;-

时间:2014-03-15 23:05:45

标签: haskell

我一直在玩Haskell一段时间,但我还没有完全掌握如何使用在Monad中运行的第三方功能。每次我回去阅读有关Monads等的文章时,我都会有很好的理解,但是当涉及到将它们应用于真实世界的代码时,我无法理解为什么一段代码不起作用。我求助于试验和错误,并且通常将其编译,但我觉得我应该能够在第一次正确使用它们而不试图通过我的启发式更改(尝试let, <-, liftM,等)。

所以我想基于这个简单的函数提出一些问题,这些函数肯定会做很多有趣的事情。

import Text.XML.HXT.Core
import Text.HandsomeSoup
import Data.String.Utils

function h = do
    let url  = myUrlBuilder h
        doc  = fromUrl url
        res  = runX $ doc >>> css "strong" /> getText 
        --nres = liftM rmSpaceAndBang (res) 
    res

rmSpaceAndBang ps =  map (\x-> replace "!" "" (strip x))  ps

以上代码编译。我有目的地省略了类型声明,因为我认为它不应该编译。所以这是我的问题。

为什么我不能res <- runX ...并以这种方式返回res

为什么res必须在let语句中,而不是绑定操作的结果?据我了解,do x <- a1; a2相当于a1 >>= \x -> a2。当let x = a1时,情况有何不同?

当我使用<-时,我收到了以下错误,如果不是因为我的试错法,我就无法弄清楚我需要在这里使用let

Couldn't match type `[]' with `IO'
Expected type: IO String
  Actual type: [String]

虽然我专注于上面的res,但我缺乏理解也适用于函数中的其他let语句。

如何找到res的返回类型?

我无法找到一种方法来搜索getText的hackage(hxt似乎太大而无法逐个模块查看。可能会在下次尝试Google网站搜索)。最后,我最终在GHCi中输入了代码的某些部分,然后:t res。它告诉我它是[String]。有一个更好的方法吗?

由于res的类型为[String],我以为我会将[String]作为函数的返回类型。但是GHC说它应该是IO [String](编译)。为什么:t首先给我错误的信息?

当函数返回IO String时,在它们上使用纯函数的最佳方法是什么?

现在我被困在IO [String]里面我需要用它来提升我做弦乐操作的所有地方。有更好的方法吗?

希望我能从中学到足够的东西,我将能够使用正确的语法,而不必盲目尝试一些组合。

更新:

我遗失的关键部分是事实res不是一个值,而是一个动作。所以我有两个选择:一个是我上面的代码let res =,但最后调用它,另一个是res <-但是然后执行return (res)

使用res <-的好处是我可以摆脱liftM res现在是[String](请参阅下面的@ duplode&#39;答案)。

谢谢!

2 个答案:

答案 0 :(得分:5)

在您的代码中,resIO [String]。我不怀疑你最初通过GHCi [String],但我相信你用

进行了测试
>>> res <- runX $ doc >>> css "strong" /> getText
>>> :t res
res :: [String]

这与您的代码不相同。不同之处在于,let只会绑定您的IO [String]操作而不运行它,而<-块中的do会运行操作并绑定结果 ,在本例中为[String]

  

现在我被困在IO [String]里面,我需要用来解除   到处都是字符串操作。有更好的方法吗?

在do块中,有时写起来更方便:

res <- runX $ doc >>> css "strong" /> getText
return $ rmSpaceAndBang res

这完全等同于使用liftM(或fmap):

liftM rmSpaceAndBang $ doc >>> css "strong" /> getText

答案 1 :(得分:4)

要快速回答,不要运行任何东西,它只是将lhs作为rhs的同义词。

实际上你需要在do中执行一个monadic函数来执行计算。

  main = do 
     let func = print "I need to be called"
     print "I don't need to be called"
     func

输出:

  "I don't need to be called"
  "I need to be called"

因此代码中的res不是值,它是一个monadic动作/函数。

请注意,<->>=绑定,并且在rhs上需要a -> m b

我们没有要求。