学习Haskell,滚动你自己的机器人示例

时间:2013-11-09 03:21:28

标签: haskell bots

我开始学习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

-

我看不出问题,似乎没有人遇到过这个问题。

3 个答案:

答案 0 :(得分:2)

我认为这是bracket中的API更改。它的当前类型是

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

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

在此代码段中,a(putStrLn "done")片段都是值,而不是函数。这可能适用于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

答案 1 :(得分: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)

由于我们没有清理任何资源,因此我们忽略了额外的论点。

此外,类型名称始终是capatilized,因此Bot,而不是bot

答案 2 :(得分: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。显然这不可能是真的!