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

これはコードです:(私は埋め込まれたタブをチェックし、すべてが同じcomlumnにあることを確認しました):

--
-- 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

のAPI変更だと思いますbracket。現在のタイプは

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

ここで、最初のアクション (「オープニング」アクション) の結果は、2 番目と 3 番目のアクションの両方に渡されます。このようにして、開始アクションは、クリーンアップ中に物事を閉じるために使用される「キー」を返すことができます。

ただし、このコード スニペットでは、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
于 2013-11-09T03:31:04.743 に答える
1

問題はのタイプbracketです

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

したがって、最初の でリソースを作成し、2 番目の部分でIO aリソースを取得してクリーンアップする cleanup を添付し、a3 番目にメイン ブロックを作成します。

しかしputStrLn :: String -> IO ()、適用されるとIO ()() -> IO ()ブラケットが望んでいるわけではありません。と同じでa、どちらも関数ではありません。

これは簡単に修正できます

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

リソースをクリーンアップしていないため、余分な引数を無視するだけです。

さらに、型名は常に大文字であるためBot、 , ではありませんbot

于 2013-11-09T03:32:21.967 に答える
0

2つの小さな問題。まず、次のタイプを見てくださいbracket

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

最初の引数はリソースを生成するためのもので、2 番目の引数はそれを解放するためのものであり、3 番目の引数はそれを使用して何らかの有用な処理を行うためのものです (例外をスローする可能性があります)。したがって、2 番目と 3 番目の関数は引数を取りますが、これは無視できます。

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

次に、次の型シグネチャを記述しましたconnect

connect :: IO bot

ここbotは型変数です。あなたが欲しいBot、型コンストラクタ:

connect :: IO Bot

あなたの型署名は現在、それが何らかのI/Oを行い、それが呼び出す任意の型connectの値を返すと言っています。明らかに、それは真実ではありません。bot

于 2013-11-09T03:31:45.493 に答える