【问题标题】:Haskell Curl HelpHaskell Curl 帮助
【发布时间】:2011-05-10 14:50:54
【问题描述】:

好的,我正试图围绕 Haskell 中的 IO 进行研究,我想我会编写一个处理网页的简短小应用程序来完成它。我被绊倒的 sn-p 是(向bobince 道歉,但公平地说,我不想在这里解析 HTML,只是提取一两个值):

titleFromUrl url = do
    (_, page) <- curlGetString url [CurlTimeout 60]   
    matchRegex (mkRegexWithOpts "<title>(.*?)</title>" False True) page

上面应该采用字符串形式的 URL,用matchRegex 扫描它指向的页面,并返回NothingJust [a],其中a 是匹配的(可能是多行的)字符串。令人沮丧的是,当我尝试这样做时

Prelude> (_, page) <- curlGetString url [CurlTimeout 60]
Prelude> matchRegex (mkRegexWithOpts "<title>(.*?)</title>" False True) page

在解释器中,它完全符合我的要求。当我尝试从文件加载相同的表达式并关联imports 时,它给了我一个类型推断错误,指出它couldn't match expected type 'IO b' against inferred type 'Maybe [String]'。这告诉我我错过了一些小而基本的东西,但我不知道是什么。我尝试将page 显式转换为字符串,但这只是迷信编程(在任何情况下都不起作用)。

有什么提示吗?

【问题讨论】:

    标签: haskell curl types type-conversion


    【解决方案1】:

    是的,GHCi 接受任何类型的值。你可以说:

    ghci> 4
    4
    ghci> print 4
    4
    

    但这两个值(4print 4)显然不相等。 GHC 的神奇之处在于,如果您输入的内容评估为IO something,那么它会执行该操作(如果something 不是(),则打印结果)。如果没有,那么它会在该值上调用show 并打印它。无论如何,您的程序无法访问此魔法。

    当你说:

    do foo <- bar :: IO Int
       baz
    

    baz 应为IO something 类型,否则为类型错误。这会让你执行 I/O,然后返回一个纯值。您可以通过注意到对上述产量进行脱糖来检查:

    bar >>= (\foo -> baz)
    

    -- (specializing to IO for simplicity)
    (>>=) :: IO a -> (a -> IO b) -> IO b
    

    因此

    bar :: IO a
    foo :: a
    baz :: IO b
    

    解决方法是使用return函数将你的返回值变成一个IO值:

    return :: a -> IO a  -- (again specialized to IO)
    

    你的代码是:

    titleFromUrl url = do
        (_, page) <- curlGetString url [CurlTimeout 60]   
        return $ matchRegex (mkRegexWithOpts "<title>(.*?)</title>" False True) page
    

    对于上面的大部分讨论,您可以将任何 monad 替换为 IO(例如 Maybe[]、...),它仍然是正确的。

    【讨论】:

    • 它有效,但只是作为后续;我是否正确理解这基本上意味着我不能从执行 IO 的函数返回常规字符串?它应该是IO String(或者,如上例中的IO (Maybe [String])?如果我想做一些事情,比如将titleFromUrl的返回值与另一个字符串连接起来,或者在没有Just [~a]的情况下打印出来包装它?对不起,如果这是一个愚蠢的问题,我对强类型的东西有点陌生。
    • 没关系,只需要绑定即可。如果你有一个类型为IO a 的值m,那么你可以写do { x &lt;- m; stuff },而x 的类型是a,你可以对它做任何你想做的事情。唯一的限制是stuff 必须是某种IO 值,可以是值或函数调用,也可以是更多&lt;- 绑定。所以,你可以用里面的String 做任何事情,只要你最终返回一个IO 东西。我建议阅读 monad 教程。有很多,这里有两个:blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html 或 LYAH 第 11 章和第 12 章。
    • [facepalm] 好的,我认为链接有帮助。我忘记了你不能用一种懒惰的、纯粹的函数式语言来保证执行顺序是错误的。您对 sn-p 的修改只是告诉编译器在任何地方使用它之前强制 matchRegex 的结果。我接近了吗?
    • @Inaimathi,不。 IO a数据结构 的类型,它表示可能进行一些 I/O 的计算,然后产生 areturn x 是表示计算的数据结构,它不进行 I/O,只返回 x。但是,是的,关于 Curl 的问题的 cmets 并不是描述一元计算的最佳场所。周围有很多教程,请使用它们。
    • 嗯,看来我有一些相当繁重的阅读工作要做。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 2011-07-03
    • 2012-01-18
    • 1970-01-01
    • 2022-01-15
    • 2023-03-26
    相关资源
    最近更新 更多