When I typed following on ghci, the exception is raised:
Prelude> import Control.Exception
Prelude Control.Exception> readFile "test.txt" `catch` (const $ return "exception caught!" :: SomeException -> IO String)
"*** Exception: test.txt: hGetContents: invalid argument (invalid byte sequence)
I do not understand why the exception is not caught. I run the above with stack ghci command on Windows 7.
("test.txt" file contains some random Japanese Letters encoded in UTF8, but I expect exception should be caught anyway)
Can someone explain why?
Since readFile returns a lazy String, it won't evaluate the file content until it is used, in this case, when ghci prints it. You can catch it by forcing to evaluate its content.
import Control.Exception
import Control.DeepSeq
(readFile "test.txt" >>= evaluate . force) `catch` (const $ return "exception caught!" :: SomeException -> IO String)
This problem is caused by lazy IO and Windows' default locale encoding.
Contrary to your assumption, the file is actually read after readFile "test.txt"catch(const $ return "exception caught!" :: SomeException -> IO String).
By lazy IO, the content of file is read only when the result value is actually evaulated.
And the exception you met is caused only when reading the content (explain below).
Evaluating forcibly the file make the catch function do catch:
> (print . length =<< readFile "test.txt") `catch` (const $ putStrLn "Exception caught" :: SomeException -> IO ())
Exception caught
In this example, the file is actually read when applying length function, then caught by the catch function.
In addition, the exception is caused because some (perhaps the first) character of test.txt is incompatible with the default character encoding of the handle,
which is CP932 in Japanese Windows.
Try inserting some ASCII characters before the invalid Japanese characters,
then you'd find the exception is really thrown when printing (actually evaluating the content of test.txt):
$ cat .\test.txt
abc介
$ stack exec ghci
> import Control.Exception
> readFile "test.txt" `catch` (const $ return "exception caught!" :: SomeException -> IO String)
"abc\33673*** Exception: test.txt: hGetContents: invalid argument (invalid byte sequence)
If you can read Japanese, see the first section of https://haskell.jp/blog/posts/2017/windows-gotchas.html, written by me! :)
Related
I have a Haskell application which uses optparse-applicative library for CLI arguments parsing. My data type for CLI arguments contains FilePaths (both files and directories), Doubles and etc. optparse-applicative can handle parse errors but I want to ensure that some files and some directories exist (or don't exist), numbers are >= 0 and etc.
What can be done is an implementation of a bunch of helper functions like these ones:
exitIfM :: IO Bool -> Text -> IO ()
exitIfM predicateM errorMessage = whenM predicateM $ putTextLn errorMessage >> exitFailure
exitIfNotM :: IO Bool -> Text -> IO ()
exitIfNotM predicateM errorMessage = unlessM predicateM $ putTextLn errorMessage >> exitFailure
And then I use it like this:
body :: Options -> IO ()
body (Options path1 path2 path3 count) = do
exitIfNotM (doesFileExist path1) ("File " <> (toText ledgerPath) <> " does not exist")
exitIfNotM (doesDirectoryExist path2) ("Directory " <> (toText skKeysPath) <> " does not exist")
exitIfM (doesFileExist path3) ("File " <> (toText nodeExe) <> " already exist")
exitIf (count <= 0) ("--counter should be positive")
This looks too ad-hoc and ugly to me. Also, I need similar functionality for almost every application I write. Are there some idiomatic ways to deal with this sort of programming pattern when I want to do a bunch of checks before actually doing something with data type? The less boilerplate involved the better it is :)
Instead of validating the options record after it has been constructed, perhaps we could use applicative functor composition to combine argument parsing and validation:
import Control.Monad
import Data.Functor.Compose
import Control.Lens ((<&>)) -- flipped fmap
import Control.Applicative.Lift (runErrors,failure) -- form transformers
import qualified Options.Applicative as O
import System.Directory -- from directory
data Options = Options { path :: FilePath, count :: Int } deriving Show
main :: IO ()
main = do
let pathOption = Compose (Compose (O.argument O.str (O.metavar "FILE") <&> \file ->
do exists <- doesPathExist file
pure $ if exists
then pure file
else failure ["Could not find file."]))
countOption = Compose (Compose (O.argument O.auto (O.metavar "INT") <&> \i ->
do pure $ if i < 10
then pure i
else failure ["Incorrect number."]))
Compose (Compose parsy) = Options <$> pathOption <*> countOption
io <- O.execParser $ O.info parsy mempty
errs <- io
case runErrors errs of
Left msgs -> print msgs
Right r -> print r
The composed parser has type Compose (Compose Parser IO) (Errors [String]) Options. The IO layer is for performing file existence checks, while Errors is a validation-like Applicative from transformers that accumulates error messages. Running the parser produces an IO action that, when run, produces an Errors [String] Options value.
The code is a bit verbose but those argument parsers could be packed in a library and reused.
Some examples form the repl:
Λ :main "/tmp" 2
Options {path = "/tmp", count = 2}
Λ :main "/tmpx" 2
["Could not find file."]
Λ :main "/tmpx" 22
["Could not find file.","Incorrect number."]
If I run the following Java program on a Windows (10) machine (I'm posting the program here for the sake of completeness):
public class IdleServer {
public static void main(String[] args) throws IOException, InterruptedException {
ServerSocket serverSock = new ServerSocket(9090);
Socket sock = serverSock.accept();
while (true) Thread.sleep(1000);
}
}
and then I connect to the Java server from Haskell:
readWithinNSecs :: IO ()
readWithinNSecs = withSocketsDo $ do
h <- connectTo "localhost" (PortNumber 9090)
hSetBuffering h NoBuffering
readerTid <- forkIO $ reader h
threadDelay $ 2 * 10^6
putStrLn "Killing the reader"
killThread readerTid
putStrLn "Reader thread killed"
where
reader h = do
line <- strip <$> hGetLine h
putStrLn $ "Got " ++ line
then the Haskell program will hang when trying to kill the process that is trying to read from the handle. Killing the Java server will cause the Haskell program to terminate, giving also the error:
<socket: 380>: hGetLine: failed (No error)
If I run the same two programs on Linux then the Haskell program terminates.
This seems to point to a bug in the base libraries of Haskell, so I reported it, but in the meantime I need to find a way to workaround this. Any ideas?
UPDATE: I posted the solution below, but it is not satisfactory: it terminates the reader thread, but it leaks resources.
import Control.Concurrent.Async
-- ...
readerAsync h = do
a <- async $ strip <$> hGetLine h
line <- wait a
putStrLn $ "Got " ++ line
I am trying out haskell's kafka library from git and got this error.
To debug this error, i like to print stacktrace at the error line.
In python world, it is just,
import traceback; print traceback.print_exc()
(or) in java, it is
e.printStackTrace()
So, how to do the same in haskell world?
You can get stack traces in Haskell but it is not as convenient as just e.printStackTrace(). Here is a minimal example:
import Control.Exception
import Debug.Trace
getStack :: String -> SomeException -> IO a
getStack msg e = traceStack (show e) $ error msg
main :: IO ()
main = do
(head []) `catch` (getStack "error on main at head")
Finally, compile it with ghc -prof -fprof-auto StackTrace.hs and it will produce
Prelude.head: empty list
Stack trace:
Main.getStack (StackTrace.hs:5:9-56)
Main.main (StackTrace.hs:(8,9)-(9,74))
GHC.List.CAF (<entire-module>)
StackTrace.exe: error on main at head
I wrote a simple TCP-client for some device, which consumes and produces 8-byte packets (the code of send-command-receive-result function is below).
When I run it on linux, it works perfectly, being part of the loop (send-recv-send-recv-...), but on windows it receives only first msg from device (send-recv-send-send-...). The packets are still going - I could clearly see them with Wireshark - but something under my client just ignores them (or truncates to zero?). It doesn't even print "Data was read!" - looks like the reading stucks and gets killed by timeout function.
Before that, I used the sockets directly; changing to HandleStream yelded no difference at all. Wrapping main in withSocketsDo did nothing, too.
transmit :: Int -> HandleStream ByteString -> ByteString -> IO [Bytestring]
transmit delay sock packet = do
let input = timeout delay $ sock `readBlock` 8 <* putStrLn "\nData was read!"
sock `writeBlock` pack
strings <- whileJust input
return [str | Right str <- strings]
whileJust action = do
result <- action
case result of
Just a -> (:) <$> return a <*> whileJust action
Nothing -> return []
What am I doing wrong?
I've tried this:
main = do
hSetBuffering stdin NoBuffering
c <- getChar
but it waits until the enter is pressed, which is not what I want. I want to read the character immediately after user presses it.
I am using ghc v6.12.1 on Windows 7.
EDIT: workaround for me was moving from GHC to WinHugs, which supports this correctly.
Yes, it's a bug. Here's a workaround to save folks clicking and scrolling:
{-# LANGUAGE ForeignFunctionInterface #-}
import Data.Char
import Foreign.C.Types
getHiddenChar = fmap (chr.fromEnum) c_getch
foreign import ccall unsafe "conio.h getch"
c_getch :: IO CInt
So you can replace calls to getChar with calls to getHiddenChar.
Note this is a workaround just for ghc/ghci on Windows. For example, winhugs doesn't have the bug and this code doesn't work in winhugs.
Might be a bug:
http://hackage.haskell.org/trac/ghc/ticket/2189
The following program repeats inputted characters until the escape key is pressed.
import IO
import Monad
import Char
main :: IO ()
main = do hSetBuffering stdin NoBuffering
inputLoop
inputLoop :: IO ()
inputLoop = do i <- getContents
mapM_ putChar $ takeWhile ((/= 27) . ord) i
Because of the hSetBuffering stdin NoBuffering line it should not be necessary to press the enter key between keystrokes. This program works correctly in WinHugs (sep 2006 version). However, GHC 6.8.2 does not repeat the characters until the enter key is pressed. The problem was reproduced with all GHC executables (ghci, ghc, runghc, runhaskell), using both cmd.exe and command.com on Windows XP Professional...
Hmm.. Actually I can't see this feature to be a bug. When you read stdin that means that you want to work with a "file" and when you turn of buffering you are saying that there is no need for read buffer. But that doesn't mean that application which is emulating that "file" should not use write buffer. For linux if your terminal is in "icanon" mode it doesn't send any input until some special event will occur (like Enter pressed or Ctrl+D). Probably console in Windows have some similar modes.
The Haskeline package worked for me.
If you need it for individual characters, then just change the sample slightly.
getInputLine becomes getInputChar
"quit" becomes 'q'
++ input becomes ++ [input]
main = runInputT defaultSettings loop
where
loop :: InputT IO ()
loop = do
minput <- getInputChar "% "
case minput of
Nothing -> return ()
Just 'q' -> return ()
Just input -> do outputStrLn $ "Input was: " ++ [input]
loop
From comment of #Richard Cook:
Use hidden-char: Provides cross-platform getHiddenChar function.
I used the haskeline package, suggested in other answers, to put together this simple alternative to getChar. It requests input again in the case that getInputChar returns Nothing. This worked for me to get past the issue; modify as needed.
import System.Console.Haskeline
( runInputT
, defaultSettings
, getInputChar
)
betterInputChar :: IO Char
betterInputChar = do
mc <- runInputT defaultSettings (getInputChar "")
case mc of
Nothing -> betterInputChar
(Just c) -> return c