Suppose I have some code written like so:
import Control.Exception (bracketOnError, finally, mask)
import Client (acquireB, releaseB, doStuff) -- theoretical
import MyStuff (preliminary, doMoreStuff) -- theoretical
clientAction = bracketOnError acquireB releaseB $ \b ->
doStuff b
return (b, releaseB b)
myAction = mask $ \restore ->
a <- preliminary
(thing, releaseThing) <- restore clientAction
doMoreStuff a thing `finally` releaseThing
I have to do some preliminary stuff, my client acquires b and then has to doStuff with b, and then I have to doMoreStuff with b. And b needs to be released, even if an asynchronous exception occurs. But I don't know how to release b, so my client tells me how. Written this way, we are both prepared to release b if an exception happens during "our" code.
My question is this: Is it ever possible for an async exception to cause releaseB not to be performed? Specifically, is there a gap between "my code" and "my client's code" where an async exception can squeeze in? Let me inline clientAction and bracketOnException to explain.
myAction = mask $ \restore -> do
a <- preliminary
(thing, releaseThing) <- restore $ mask $ \restore2 -> do
b <- acquireB
restore2 (doStuff b >> return (b, releaseB b))
`onException` releaseB b
doMoreStuff a thing `finally` releaseThing
The concern is this: is there a moment right here
... restore $ mask ...
Right when the client's mask is lifted, but before the end of my restore surrounding it, where an exception could sneak through?
Yes, in GHC, when the unmask occurs we eagerly check for blocked exceptions and raise them.
Related
I write a function that print all contents of file like that
let rec print_file channel =
try
begin
print_endline (input_line channel);
print_file channel
end
with End_of_file -> ()
And because of print_file is last operation I was thinking that it will be optimized to regular loop. but when I had runned my program on really big file, I had got stack overflow.
So I has tried to wrap input_line function to input_line_opt that don't raise exception and little change code of print_file.
let input_line_opt channel =
try Some (input_line channel)
with End_of_file -> None
let rec print_file channel =
let line = input_line_opt channel in
match line with
Some line -> (print_endline line; print_file channel)
| None -> ()
And now it works like regular tail recursive function and don't overflow my stack.
What difference between this two function?
In the first example, try ... with is an operation that occurs after the recursive call to print_file. So the function is not tail recursive.
You can imagine that try sets up some data on the stack, and with removes the data from the stack. Since you remove the data after the recursive call, the stack gets deeper and deeper.
This was a consistent problem in earlier revisions of OCaml. It was tricky to write tail-recursive code for processing a file. In recent revisions you can use an exception clause of match to get a tail position for the recursive call:
let rec print_file channel =
match input_line channel with
| line -> print_endline line; print_file channel
| exception End_of_file -> ()
My main goal is to redirect stderr to a file.
I got hold of the following code snippet...
catchOutput :: IO a -> IO (res, String)
catchOutput f = do
tmpd <- getTemporaryDirectory
(tmpf, tmph) <- openTempFile tmpd "haskell_stderr"
stderr_dup <- hDuplicate stderr
hDuplicateTo tmph stderr
hClose tmph
res <- f
hDuplicateTo stderr_dup stderr
str <- readFile tmpf
removeFile tmpf
return (res, str)
I hoped to make this more general and pass any function and argument list to catchOutput and get the function result as well as message written to stderr (if any).
I thought that an argument list of type [Data.Dynamic] might work but I failed to retrieve the function result with
res <- Data.List.foldl (f . fromDyn) Nothing $ args
Is this even possible? Help will be greatly appreciated.
There is not reason to use Data.Dynamic. You already know type the return type of f, it's a so you can use just that, i.e.
catchOutput :: IO a -> IO (a, String)
Note though, that there some significant issues with your approach:
By redirecting stderr to a file, this will also affect all other concurrent threads. So you could possibly get unrelated data sent to the temporary file.
If an exception is thrown while stderr is redirected, the original stderr will not be restored. Any operation between the two hDuplicateTo lines (hClose and f in this case) could possibly throw an exception, or the thread may receive an asynchronous exception. For this reason, you have to use something like bracket to make your code exception safe.
Ok, this is mostly about curiosity but I find it too strange.
Let's suppose I have this code
sig.mli
type t = A | B
main.ml
let f =
let open Sig in
function A | B -> ()
If I compile, everything will work.
Now, let's try to modify sig.mli
sig.mli
type t = A | B
exception Argh
and main.ml
main.ml
let f =
let open Sig in
function
| A -> ()
| B -> raise Argh
And let's try to compile it :
> ocamlc -o main sig.mli main.ml
File "main.ml", line 1:
Error: Error while linking main.cmo:
Reference to undefined global `Sig'
Well, is it just because I added the exception ? Maybe it means that exceptions are like functions or modules, you need a proper implementation.
But then, what if I write
main.ml
let f =
let open Sig in
function A | B -> ()
And try to compile ?
> ocamlc -o main sig.mli main.ml
>
It worked ! If I don't use the exception, it compiles !
There is no reason to this behaviour, right ? (I tested it on different compilers, 3.12.0, 4.00.0, 4.02.3 and 4.03.0 and all of them gave the same error)
Unlike variants, exception is not a pure type and requires its implementation in .ml file. Compile the following code with ocamlc -dlambda -c x.ml:
let x = Exit
-- the output --
(setglobal X!
(seq (opaque (global Pervasives!))
(let (x/1199 = (field 2 (global Pervasives!)))
(pseudo _none_(1)<ghost>:-1--1 (makeblock 0 x/1199)))))
You can see (let (x/1999 = (field 2 (global Pervasives!))).. which means assigning the value stored in the 2nd position of module Pervasives. This is the value of Exit. Exceptions have their values and therefore need .ml.
Variants do not require implementation. It is since their values can be constructed purely from their type information: constructors' tag integers. We cannot assign tag integers to exceptions (and their generalized version, open type constructors) since they are openly defined. Instead they define values for their identification in .ml.
To get an implementation of the exception, you need sig.ml. A .mli file is an interface file, a .ml file is an implementation file.
For this simple example you could just rename sig.mli to sig.ml:
$ cat sig.ml
type t = A | B
exception Argh
$ cat main.ml
let f =
let open Sig in
function
| A -> ()
| B -> raise Argh
$ ocamlc -o main sig.ml main.ml
I don't see a problem with this behavior, though it would be nice not to have to duplicate types and exceptions between .ml and .mli files. The current setup has the advantage of being simple and explicit. (I'm not a fan of compilers being too clever and doing things behind my back.)
I'm using hedis and trying to handle the case of the server going dead. According to the documentation:
Connection to the server lost:
In case of a lost connection, command functions throw a ConnectionLostException. It can only be caught outside of runRedis.
So I would assume I want to catch the ConnectionLostException. However, whilst I can seem to catch it correctly, it seems to also bubble up to the top, and I'm not sure why. Here's some code (just running in GHCI):
:set -XOverloadedStrings
import Database.Redis
import Control.Exception
conn <- connect defaultConnectInfo
runRedis conn $ ping
Now, if I kill the redis server between making the connection and running the command, I get the result I expect:
⟨interactive⟩: ConnectionLost
*** Exception: ConnectionLost
So instead I try to do the following (I added >>= evaluate in order to attempt to force evaluation of the error, but it made no difference):
let tryR = try :: IO a -> IO (Either ConnectionLostException a)
tryR . (>>= evaluate) . runRedis conn $ ping
This gives me:
Left Con: ConnectionLost
nectionLost
So I'm getting the Left result as expected, but halfway through the exception is also presumably being caught and displayed by GHCI. Is this a problem with things not being evaluated?
Like John hinted, there seems to be somthing that prints this message to stderr.
Consider this example:
{-# LANGUAGE OverloadedStrings #-}
import Control.Concurrent (threadDelay)
import Control.Exception
import Control.Monad
import Database.Redis
import System.Mem
tryR :: IO a -> IO (Either ConnectionLostException a)
tryR = try
main :: IO ()
main = do
conn <- connect defaultConnectInfo
loop conn
putStrLn $ "exiting gracefully after counting up some numbers"
performGC
forM_ [1..10] $ \i -> do
print i
threadDelay 10000 -- 0.05 seconds
where
loop conn = do
e <- tryR . (>>= evaluate) . runRedis conn $ ping
case e of
Right x -> do print x
threadDelay 1000000
loop conn
Left err -> do putStrLn $ "tryR caught exception: " ++ show err
It prints:
Right Pong
Right Pong <-------------- after this I Ctrl-C the redis server
tryR caught exception: ConnectionLost
exiting gracefully after counting up some numbers
1
test: ConnectionLost
2
3
4
5
6
7
8
9
10
This looks like something in the stack is printing this test: ConnectionLost (or test.hs: ConnectionLost if you use GHCI/runghc) asynchronously.
If that's GHC, that is probably a bug, but chances are high it is done by hedis or one of its dependencies (I haven't found it in hedis itself yet).
hello I am making some word searching program
for example
when "text.txt" file contains "foo foos foor fo.. foo fool"
and search "foo"
then only number 2 printed
and search again and again
but I am haskell beginner
my code is here
:module +Text.Regex.Posix
putStrLn "type text file"
filepath <- getLine
data <- readFile filepath
--1. this makes <interactive>:1:1: parse error on input `data' how to fix it?
parsedData =~ "[^- \".,\n]+" :: [[String]]
--2. I want to make function and call it again and again
searchingFunc = do putStrLn "search for ..."
search <- getLine
result <- map (\each -> if each == search then count = count + 1) data
putStrLn result
searchingFunc
}
sorry for very very poor code
my development environment is Windows XP SP3 WinGhci 1.0.2
I started the haskell several hours ago sorry
thank you very much for reading!
edit: here's original scheme code
thanks!
#lang scheme/gui
(define count 0)
(define (search str)
(set! count 0)
(map (λ (each) (when (equal? str each) (set! count (+ count 1)))) data)
(send msg set-label (format "~a Found" count)))
(define path (get-file))
(define port (open-input-file path))
(define data '())
(define (loop [line (read-line port)])
(when (not (eof-object? line))
(set! data (append data
(regexp-match* #rx"[^- \".,\n]+" line)))
(loop)))
(loop)
(define (cb-txt t e) (search (send t get-value)))
(define f (new frame% (label "text search") (min-width 300)))
(define txt (new text-field% (label "type here to search") (parent f) (callback (λ (t e) (cb-txt t e)))))
(define msg (new message% (label "0Found ") (parent f)))
(send f show #t)
I should start by iterating what everyone would (and should) say: Start with a book like Real World Haskell! That said, I'll post a quick walkthrough of code that compiles, and hopefully does something close to what you originally intended. Comments are inline, and hopefully should illustrate some of the shortcomings of your approach.
import Text.Regex.Posix
-- Let's start by wrapping your first attempt into a 'Monadic Action'
-- IO is a monad, and hence we can sequence 'actions' (read as: functions)
-- together using do-notation.
attemptOne :: IO [[String]]
-- ^ type declaration of the function 'attemptOne'
-- read as: function returning value having type 'IO [[String]]'
attemptOne = do
putStrLn "type text file"
filePath <- getLine
fileData <- readFile filePath
putStrLn fileData
let parsed = fileData =~ "[^- \".,\n]+" :: [[String]]
-- ^ this form of let syntax allows us to declare that
-- 'wherever there is a use of the left-hand-side, we can
-- substitute it for the right-hand-side and get equivalent
-- results.
putStrLn ("The data after running the regex: " ++ concatMap concat parsed)
return parsed
-- ^ return is a monadic action that 'lifts' a value
-- into the encapsulating monad (in this case, the 'IO' Monad).
-- Here we show that given a search term (a String), and a body of text to
-- search in, we can return the frequency of occurrence of the term within the
-- text.
searchingFunc :: String -> [String] -> Int
searchingFunc term
= length . filter predicate
where
predicate = (==)term
-- ^ we use function composition (.) to create a new function from two
-- existing ones:
-- filter (drop any elements of a list that don't satisfy
-- our predicate)
-- length: return the size of the list
-- Here we build a wrapper-function that allows us to run our 'pure'
-- searchingFunc on an input of the form returned by 'attemptOne'.
runSearchingFunc :: String -> [[String]] -> [Int]
runSearchingFunc term parsedData
= map (searchingFunc term) parsedData
-- Here's an example of piecing everything together with IO actions
main :: IO ()
main = do
results <- attemptOne
-- ^ run our attemptOne function (representing IO actions)
-- and save the result
let searchResults = runSearchingFunc "foo" results
-- ^ us a 'let' binding to state that searchResults is
-- equivalent to running 'runSearchingFunc'
print searchResults
-- ^ run the IO action that prints searchResults
print (runSearchingFunc "foo" results)
-- ^ run the IO action that prints the 'definition'
-- of 'searchResults'; i.e. the above two IO actions
-- are equivalent.
return ()
-- as before, lift a value into the encapsulating Monad;
-- this time, we're lifting a value corresponding to 'null/void'.
To load this code, save it into a .hs file (I saved it into 'temp.hs'), and run the following from ghci. Note: the file 'f' contains a few input words:
*Main Text.Regex.Posix> :l temp.hs
[1 of 1] Compiling Main ( temp.hs, interpreted )
Ok, modules loaded: Main.
*Main Text.Regex.Posix> main
type text file
f
foo foos foor fo foo foo
The data after running the regex: foofoosfoorfofoofoo
[1,0,0,0,1,1]
[1,0,0,0,1,1]
There is a lot going on here, from do notation to Monadic actions, 'let' bindings to the distinction between pure and impure functions/values. I can't stress the value of learning the fundamentals from a good book!
Here is what I made of it. It doesn't does any error checking and is as basic as possible.
import Text.Regex.Posix ((=~))
import Control.Monad (when)
import Text.Printf (printf)
-- Calculates the number of matching words
matchWord :: String -> String -> Int
matchWord file word = length . filter (== word) . concat $ file =~ "[^- \".,\n]+"
getInputFile :: IO String
getInputFile = do putStrLn "Enter the file to search through:"
path <- getLine
readFile path -- Attention! No error checking here
repl :: String -> IO ()
repl file = do putStrLn "Enter word to search for (empty for exit):"
word <- getLine
when (word /= "") $
do print $ matchWord file word
repl file
main :: IO ()
main = do file <- getInputFile
repl file
Please start step by step. IO in Haskell is hard, so you shouldn't start with file manipulation. I would suggest to write a function that works properly on a given String. That way you can learn about syntax, pattern matching, list manipulation (maps, folds) and recursion without beeing distracted by the do notation (which kinda looks imperative, but isn't, and really needs a deeper understanding).
You should check out Learn you a Haskell or Real World Haskell to get a sound foundation. What you do now is just stumbling in the dark - which may work if you learn languages that are similar to the ones you know, but definitely not for Haskell.