1

我开始学习 Haskell,发现了这个程序:http ://www.haskell.org/haskellwiki/Roll_your_own_IRC_bot/Source 。

当我输入它并使用 ghc --make 4.hs tutbot 进行编译时,我收到以下错误:

4.hs:58:10:
    Couldn't match expected type `() -> IO b0' with actual type `IO ()'
    In the return type of a call of `putStrLn'
    Probable cause: `putStrLn' is applied to too many arguments
    In the second argument of `bracket', namely `(putStrLn "done.")'
    In the expression:
      bracket
        (printf "Connecting to %s ... " server >> hFlush stdout)
        (putStrLn "done.")
        a

这是代码:(我检查了嵌入式选项卡并确保所有选项卡都在同一列中):

--
-- Connect to the server and return the initial bot state
-- 
connect :: IO bot
connect = notify $ do
    t <- getClockTime
    h <- connectTo server (PortNumber (fromIntegral port))
    hSetBuffering h NoBuffering
    return (Bot h t)
  where
    notify a = bracket
        (printf "Connecting to %s ... " server >> hFlush stdout)
        (putStrLn "done.")
        a

--

我看不到这个问题,而且似乎没有其他人遇到过这个问题。

4

3 回答 3

2

我认为这是bracket. 它的当前类型是

bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c

其中第一个动作(“打开”动作)的结果被传递给第二个和第三个动作。这样,打开动作可以返回一个“键”,用于在清理过程中关闭事物。

然而,在这个代码片段中,thea(putStrLn "done")Fragments 都是值,而不是函数。那可能是旧版本bracket

bracket :: IO a -> IO b -> IO c -> IO c

此更正可能会修复错误

connect :: IO bot
connect = notify $ \_ -> do
    t <- getClockTime
    h <- connectTo server (PortNumber (fromIntegral port))
    hSetBuffering h NoBuffering
    return (Bot h t)
  where
    notify a = bracket
        (printf "Connecting to %s ... " server >> hFlush stdout)
        (const $ putStrLn "done.")
        a
于 2013-11-09T03:31:04.743 回答
1

问题是类型bracket

IO a -> (a -> IO b) -> (a -> IO c) -> IO c

所以我们用第一个创建一个资源IO a,附加一个清理,a在第二部分中获取资源并清理它,然后主块是第三个。

但是putStrLn :: String -> IO (),当应用它时,它只是IO (),而不是() -> IO ()括号想要的。与 相同a,函数也不是。

这可以很容易地解决

...
  (const $ putStrLn "done")
  (const a)

这只是让我们忽略了这个额外的论点,因为我们没有清理任何资源。

此外,类型名称总是大写的,所以Bot, 不是bot

于 2013-11-09T03:32:21.967 回答
0

两个小问题。首先,看类型bracket

bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c

第一个参数是为了产生一个资源,第二个是释放它,第三个是用它做一些有用的事情(可能会抛出异常)。所以第二个和第三个函数有一个参数,你可以忽略它:

notify a = bracket
    (printf "Connecting to %s ... " server >> hFlush stdout)
    (\_ -> putStrLn "done.")
    (\_ -> a)

其次,您已经为以下内容编写了此类型签名connect

connect :: IO bot

这里bot是一个类型变量;你想要Bot一个类型构造函数:

connect :: IO Bot

您的类型签名当前表示它connect执行一些 I/O 并将返回它调用的任何类型bot的值。显然这不可能是真的!

于 2013-11-09T03:31:45.493 回答