我试图在Leksah的Haskell中构建一个小程序,将.lhs文件转换为.hs文件。但我无法在没有错误的情况下进行构建。任何帮助,将不胜感激。我是Haskell的新手,请原谅我,如果答案很明显,虽然我无法看到它。这是代码和错误:
-- Converts .lhs (literary Haskell files) to .hs (plain Haskell files)
-- Keeps only the statements which are normally compiled, plus blank lines.
-- To use:
-- ghc --make lhs2hs.hs
-- to get an executable file lhs2hs.
-- Then
-- lhs2hs filename
-- will open filename.lhs and save the converted file in filename.hs
-- by Scot Drysdale on 7/28/07, based on SOE program on p. 241
module Main where
import System.IO
-- import System.IO.Error (catchIOError)
import Control.Exception (catch)
import System.Environment -- to allow getArgs
-- Opens a file, given name and mode
openGivenFile :: String -> IOMode -> IO Handle
openGivenFile name mode
= catch (do handle <- openFile name mode
return handle)
handler
where
handler :: IOError -> IO Handle
-- Next line does not match IO Handle
handler ex = putStrLn $ "Caught exception: " ++ show ex
-- (\e -> error ("Cannot open " ++ name))
main = do args <- getArgs
fromHandle <- openGivenFile (args !! 0 ++ ".lhs") ReadMode
toHandle <- openGivenFile (args !! 0 ++ ".hs") WriteMode
convertFile fromHandle toHandle
hClose fromHandle
hClose toHandle
-- Converts all the lines in a file
convertFile :: Handle -> Handle -> IO ()
convertFile fromHandle toHandle
= catch (do line <- hGetLine fromHandle
case line of
('>' : ' ' : rest) -> hPutStrLn toHandle rest
('>' : rest) -> hPutStrLn toHandle rest
('\n' : rest) -> hPutStrLn toHandle line
('\r' : rest) -> hPutStrLn toHandle line
_ -> return ()
convertFile fromHandle toHandle)
handler
where
handler :: IOError -> IO ()
handler ex = putStrLn $ "Caught exception: " ++ show ex
错误是:
src\Main.hs:27:28-69:
Couldn't match type `()' with `Handle'
Expected type: IO Handle
Actual type: IO ()
In the expression: putStrLn $ "Caught exception: " ++ show ex
In an equation for `handler':
handler ex = putStrLn $ "Caught exception: " ++ show ex
In an equation for `openGivenFile':
openGivenFile name mode
= catch
(do { handle <- openFile name mode;
return handle })
handler
where
handler :: IOError -> IO Handle
handler ex = putStrLn $ "Caught exception: " ++ show ex
答案 0 :(得分:2)
签名,例如
openGivenFile :: String -> IOMode -> IO Handle
声明openGivenFile
返回Handle
,除非它抛出异常。
如果您决定在其中捕捉IOError
,那本身就没问题,但是你需要某种方法在每种情况下提出Handle
- 这是不可能的。
所以,要么你需要让异常流出,要么你需要更改签名,这样你就不再承诺Handle
而是更弱的东西了。 E.g。
openGivenFile :: String -> IOMode -> IO (Either IOError Handle)
openGivenFile name mode
= catch (do handle <- openFile name mode
return (Right handle))
handler
where
handler :: IOError -> IO (Either IOError Handle)
handler ex = do
-- since we are returning the error,
-- printing it may be a bad design now
putStrLn $ "Caught exception: " ++ show ex
return (Left ex)
经过一些清理后:
openGivenFile :: String -> IOMode -> IO (Either IOError Handle)
openGivenFile name mode = (Right <$> openFile name mode) `catch` handler
where handler :: IOError -> IO (Either IOError Handle)
handler = return . Left
即使这样也可行:
openGivenFile :: String -> IOMode -> IO (Either IOError Handle)
openGivenFile name mode =
(Right <$> openFile name mode) `catch` (return . Left)
但是被捕获的异常现在有点隐藏在整个函数的类型签名中。由于这是一个单行,它应该足够清楚,但我更喜欢以前的替代方案,因为它记录了更好地捕捉IOError
的意图。
答案 1 :(得分:0)
我让程序运转起来。谢谢志。我把答案标记为答案。这是最终的代码:
编辑:修改了文件结束检查的代码,以便在正常运行时不会出现异常。
-- Converts .lhs (literary Haskell files) to .hs (plain Haskell files)
-- Keeps only the statements which are normally compiled, plus blank lines.
-- To use:
-- ghc --make lhs2hs.hs
-- to get an executable file lhs2hs.
-- Then
-- lhs2hs filename
-- will open filename.lhs and save the converted file in filename.hs
-- by Scot Drysdale on 7/28/07, based on SOE program on p. 241
module Main where
import System.IO
import System.IO.Error
import Control.Exception (catch)
import System.Environment -- to allow getArgs
-- Opens a file, given name and mode
openGivenFile :: String -> IOMode -> IO (Either IOError Handle)
openGivenFile name mode
= catch (do handle <- openFile name mode
return (Right handle))
handler
where
handler :: IOError -> IO (Either IOError Handle)
handler ex = do
-- since we are returning the error,
-- printing it may be a bad design now
putStrLn $ "Caught exception: " ++ show ex
return (Left ex)
main = do args <- getArgs
(Right fromHandle) <- openGivenFile (args !! 0 ++ ".lhs") ReadMode
(Right toHandle) <- openGivenFile (args !! 0 ++ ".hs") WriteMode
-- (Right fromHandle) <- openGivenFile (head args) ReadMode
-- (Right toHandle) <- openGivenFile (head args) WriteMode
convertFile fromHandle toHandle
hClose fromHandle
hClose toHandle
-- Converts all the lines in a file
convertFile :: Handle -> Handle -> IO ()
convertFile fromHandle toHandle
= catch ( do ineof <- hIsEOF fromHandle
if ineof
then return ()
else do line <- hGetLine fromHandle
case line of
('>' : ' ' : rest) -> hPutStrLn toHandle rest
('>' : rest) -> hPutStrLn toHandle rest
('\n' : rest) -> hPutStrLn toHandle line
('\r' : rest) -> hPutStrLn toHandle line
_ -> return ()
convertFile fromHandle toHandle)
handler
where
handler :: IOError -> IO ()
handler ex = putStrLn $ "Caught exception: " ++ show ex