Send Beginners mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."
Today's Topics:
1. Re: STM and IO (Quentin Moser)
2. Re: Inferred type is less polymorphic than e
(Marco T?lio Gontijo e Silva)
3. Re: Inferred type is less polymorphic than e (Daniel Fischer)
4. Re: Re: [Haskell-beginners] STM and IO (emmanuel.delaborde)
5. Re: Re: [Haskell-beginners] STM and IO (Chris G)
----------------------------------------------------------------------
Message: 1
Date: Thu, 9 Apr 2009 12:16:54 +0200
From: Quentin Moser <[email protected]>
Subject: Re: [Haskell-beginners] STM and IO
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=US-ASCII
On Thu, 9 Apr 2009 12:03:03 +0200
Quentin Moser <[email protected]> wrote:
> Here's an example inspired by the documentation of Control.Concurrent:
>
> > import Control.Concurrent
> > import Control.Exception (finally)
> >
> > myFork :: IO () -> IO (MVar ())
> > myFork a = do v <- newEmptyMVar
> > a `finally` (putMVar v ())
> >
> > myWait :: MVar () -> IO ()
> > myWait = readMVar
Oops, my code is completely messed up. Here's a correct version:
> myFork a = do v <- newEmptyMVar
> forkIO $ a `finally` putMVar v ()
> return v
> myWait = readMVar >> return ()
------------------------------
Message: 2
Date: Thu, 09 Apr 2009 08:16:01 -0300
From: Marco T?lio Gontijo e Silva <[email protected]>
Subject: Re: [Haskell-beginners] Inferred type is less polymorphic
than e
To: [email protected]
Message-ID: <1239275761.6067.101.ca...@zezinho>
Content-Type: text/plain; charset=UTF-8
Em Qui, 2009-04-09 Ã s 01:55 +0200, Daniel Fischer escreveu:
> Am Donnerstag 09 April 2009 00:29:24 schrieb Marco Túlio Gontijo e Silva:
> > Hello,
> >
> > I'm getting this error message from GHC in the following code:
> > > type M a = Monad m => m a
> > >
> > > class A a b where
> > > f :: Monad m => a -> m b
> > >
> > > instance A String Char where
> > > f string = return $ head string
> > >
> > > instance A Char Int where
> > > f int = return $ fromEnum int
> >
> > I thought at first to write h like this, but it gives me the error. If
> > I write it like the other h uncommented, there's no error. I can't see
> > why they aren't equivalent.
> >
> > h :: IO ()
> > h = f "abc" >>= (f :: Char -> M Int) >>= print
> >
> > > h :: IO ()
> > > h = (f "abc" :: M Char) >>= f >>= (print :: Int -> IO ())
> >
> ----------------------------------------------------------------
> class B a b where
> foo :: a -> M b
>
> instance B String Char where
> foo str = return $ head str
>
> instance B Char Int where
> foo c = return $ fromEnum c
>
> k :: IO ()
> k = foo "abc" >>= (foo :: Char -> M Int) >>= print
> ----------------------------------------------------------------
>
> works, as does
>
> m = foo "abc" >>= (foo :: Char -> (forall x. Monad x => x Int)) >>= print
>
> And that reveals what's going on, since m is in fact the same as k.
> The type of f in class A says that given any specific monad m and a value of
> type a, f can produce a value of type m b.
> But when you write
> (f :: Char -> M Int)
> , you say that given a Char, f produces a value which belongs to m Int *for
> every monad m*. Thus the type you state for f (the expected type) is more
> polymorphic than the actual type f has according to the class definition
> (which
> is the inferred type).
Ok, I got it, so I tried changing class A in my example to:
> class A a b where
> f :: forall m . Monad m => a -> m b
so that the type of f would be as polymorphic as the type a -> M b. But
I got the same problem.
Your solution is good, but I can't do it in my real application where I
find out this problem, because the type synonym M is defined after the
class A, and it contains more than on type constraint:
> type Interpret value
> = ( MonadReader Input monad
> , MonadState Machine monad
> , MonadWriter Stream monad)
> => monad value
My use is that I have some classes defined in modules included by the
one that defines type Interpret, like this:
> class Value pointer value where
> getValue
> :: (MonadReader Program monad, MonadState Machine monad)
> => pointer -> monad value
And even if they were defined in the same file, it would not be good to
define them as Interpret, because it would restrict its type.
Another thing: I understand your explanation, but I don't get why this
makes the other h definition valid. Could you clarify me on that?
Thanks.
--
marcot
http://marcot.iaaeee.org/
------------------------------
Message: 3
Date: Thu, 9 Apr 2009 16:52:25 +0200
From: Daniel Fischer <[email protected]>
Subject: Re: [Haskell-beginners] Inferred type is less polymorphic
than e
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="utf-8"
Am Donnerstag 09 April 2009 13:16:01 schrieb Marco Túlio Gontijo e Silva:
> Em Qui, 2009-04-09 Ã s 01:55 +0200, Daniel Fischer escreveu:
> Ok, I got it, so I tried changing class A in my example to:
> > class A a b where
> > f :: forall m . Monad m => a -> m b
>
> so that the type of f would be as polymorphic as the type a -> M b. But
> I got the same problem.
Because that's exactly the same type f had before.
To get a polymorphic result from f, you have to declare
{-# LANGUAGE Rank2Types #-}
-- or make it RankNTypes and be ready for more quantification
class A a b where
f :: a -> (forall m. Monad m => m b)
>
> Your solution is good, but I can't do it in my real application where I
> find out this problem, because the type synonym M is defined after the
>
> class A, and it contains more than on type constraint:
> > type Interpret value
> > = ( MonadReader Input monad
> > , MonadState Machine monad
> > , MonadWriter Stream monad)
> > => monad value
>
> My use is that I have some classes defined in modules included by the
>
> one that defines type Interpret, like this:
> > class Value pointer value where
> > getValue
> >
> > :: (MonadReader Program monad, MonadState Machine monad)
> >
> > => pointer -> monad value
>
> And even if they were defined in the same file, it would not be good to
> define them as Interpret, because it would restrict its type.
>
> Another thing: I understand your explanation, but I don't get why this
> makes the other h definition valid. Could you clarify me on that?
This definition?
> > > h :: IO ()
> > > h = (f "abc" :: M Char) >>= f >>= (print :: Int -> IO ())
Let's start on the left:
(f "abc" :: M Char) === (f "abc" :: forall m. Monad m => m Char)
Now we have
class A a b where
f :: Monad m => a -> m b
instance A String Char where ...
We apply f to the String "abc", so an "instance A String b" has to be selected.
f will here be invoked at the type
(A String b, Monad m) => String -> m b
=== forall m b. (A String b, Monad m) => String -> m b
Therefore f "abc" has the type resulting from removing the argument type, namely
f "abc" :: forall m b. (A String b, Monad m) => m b
Note that although f does not have the type
(A String b) => String -> (forall m. Monad m => m b)
the expression (f string) has the type forall b m. (A String b, Monad m) => m b.
It's the same with return, the type of return is
forall a m. Monad m => a -> m a
and not
forall a. a -> (forall m. Monad m => m a),
but the type of return value is (forall m. Monad m => m a), where a is the type
of value.
Now f "abc" has a type annotation, f "abc" :: M Char, or
f "abc" :: forall m. Monad m => m Char
That type must now be unified with the inferred type,
forall mon b. (A String b, Monad mon) => mon b.
It is obvious that we must have b === Char, so the compiler looks for an
instance A String Char where... (or a more general instance)
Since there is one, that is fine and the satisfied constraint (A String Char)
can be
removed. The two type(-constructor) variables m and mon are now unified and
there contexts
united. Since both contexts are the same, the result is
f "abc" :: forall m. Monad m => m Char,
exactly the specified signature (can't be anything else, if the inferred type
were less
polymorphic than the specified, it wouldn't compile, if it's more general, it's
restricted
to the specified type).
On to the next step, look at
(f "abc" :: M Char) >>= f
(>>=) :: Monad m => m u -> (u -> m v) -> m v
(f "abc") :: Monad mo => mo Char
f :: (A a b, Monad mon) => a -> mon b
Now we have to unify mo Char with m u (the contexts Monad m and Monad mo will
be taken
care of thereafter).
That's easy, u == Char and m === mo, contexts are the same, so
((f "abc" :: M Char) >>=) :: Monad m => (Char -> m v) -> m v
Next we must unify
Char -> m v
with
a -> mon b.
That's again easy, a === Char, mon === m, b === v.
Now take the contexts (Monad m) and (A a b, Monad mon) into account.
Substituting int f's context, we get the context (A Char v, Monad m) for f's
type here,
so this f is called at the type (A Char v, Monad m) => Char -> m v, and we get
the type
(f "abc" :: M Char) >>= f :: (A Char v, Monad m) => m v
Finally,
left :: (A Char v, Monad m) => m v
(>>=) :: Monad mo => mo a -> (a -> mo b) -> mo b
print :: Int -> IO () -- specified
We get the type
(left >>=) :: (A Char v, Monad m) => (v -> m b) -> m b
and then must unify (v -> m b) with (Int -> IO ()), giving v === Int, m === IO,
b === ().
Substituting into the contexts gives
(left >>= print) :: (A Char Int, Monad IO) => IO ()
The context doesn't contain any type variables and the conditions are
fulfilled, so the
context is removed, leaving
(f "abc" :: M Char) >>= f >>= (print :: Int -> IO ()) :: IO ().
>
> Thanks.
------------------------------
Message: 4
Date: Thu, 9 Apr 2009 17:20:19 +0100
From: "emmanuel.delaborde" <[email protected]>
Subject: Re: Re: [Haskell-beginners] STM and IO
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="us-ascii"
>
> From: Quentin Moser <[email protected]>
> Subject: Re: [Haskell-beginners] STM and IO
>
> Your problem has nothing to do with lazyness; Haskell simply kills all
> other threads when the main thread returns from main. You have to
> somehow wait for them to complete in main or they won't have time to
> run.
Doh!
I've been bitten before...
> Now onto the second problem: ignore me if I'm wrong, but it seems your
> intent is to spawn 10 threads that will each try to run (writeTo
> store)
> once. What your current code does is spawn one thread that
> sequentially
> runs writeTo 10 times.
yes you are right of course
> Note: I haven't tried running any of this code, but it seems simple
> enough to be confident in.
I had to make a change to myFork to get it to compile, here's what I
have now:
module Main where
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import System.IO
import Control.Exception (finally)
myFork :: IO () -> IO (MVar ())
myFork a = do
v <- newEmptyMVar
a `finally` (putMVar v ())
return v -- to honor the return type
myWait :: MVar () -> IO ()
myWait = readMVar
main = do
let fname = "store.txt"
fh <- openFile fname ReadWriteMode
store <- atomically $ newTMVar fh
waitMes <- 10 `replicateM` (myFork $ writeTo store)
mapM_ myWait waitMes
writeTo :: TMVar (Handle) -> IO ()
writeTo store = do
fh <- atomically $ takeTMVar store
text <- hGetContents fh
hPutStr fh (text ++ " some text ")
atomically $ putTMVar store fh
Now I get the following error : test3: store.txt: hPutStr: illegal
operation (handle is closed)
reading the doc about hGetContents, I found that : "Computation
hGetContents hdl returns the list of characters corresponding to the
unread portion of the channel or file managed by hdl, which is put
into an intermediate state, semi-closed. In this state, hdl is
effectively closed"
Intuitively I'd want to write something like : writeTo filename =
atomically (do { s <- readFile filename ; writeFile filename (s ++
"blah") })
but the type system prevents me from doing IO within STM
I do not know how to go about sharing access to a file between
multiple threads using STM... any pointers ?
Thanks
E.
--
Emmanuel Delaborde
Web Technologist
Cimex
53-55 Scrutton Street, London UK, EC2A 4PJ
T: +44 (0)20 7324 7780
F: +44 (0)20 7324 7781
http://www.cimex.com
-----------------------------------------------------------------------------------------------
This e-mail (and any attachments) is confidential and may contain
personal views which are not the views of Cimex Media Ltd and
any affiliated companies, unless specifically stated. It is intended
for the use of the individual or group to whom it is addressed. If
you have received it in error, please delete it from your system,
do not use, copy or disclose the information in any way nor act in
reliance on it and please notify [email protected]
A company registered in England Wales. Company Number 03765711
Registered Office : The Olde Bakehouse, 156 Watling Street East, Towcester,
Northants NN12 6DB
This email was scanned by Postini, the leading provider in Managed Email
Security.
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
http://www.haskell.org/pipermail/beginners/attachments/20090409/4a6d0b40/attachment-0001.htm
------------------------------
Message: 5
Date: Thu, 9 Apr 2009 13:56:23 -0400
From: Chris G <[email protected]>
Subject: Re: Re: [Haskell-beginners] STM and IO
To: "emmanuel.delaborde" <[email protected]>
Cc: [email protected]
Message-ID:
<[email protected]>
Content-Type: text/plain; charset="iso-8859-1"
Since the file handle is closed after you read the contents, you need to
open a new one before writing to it.
On Thu, Apr 9, 2009 at 12:20 PM, emmanuel.delaborde <
[email protected]> wrote:
>
> From: Quentin Moser <[email protected]>
> Subject: Re: [Haskell-beginners] STM and IO
>
> Your problem has nothing to do with lazyness; Haskell simply kills all
> other threads when the main thread returns from main. You have to
> somehow wait for them to complete in main or they won't have time to
> run.
>
>
> Doh!
> I've been bitten before...
>
> Now onto the second problem: ignore me if I'm wrong, but it seems your
> intent is to spawn 10 threads that will each try to run (writeTo store)
> once. What your current code does is spawn one thread that sequentially
> runs writeTo 10 times.
>
>
> yes you are right of course
>
> Note: I haven't tried running any of this code, but it seems simple
> enough to be confident in.
>
>
> I had to make a change to myFork to get it to compile, here's what I have
> now:
>
> module Main where
>
> import Control.Monad
> import Control.Concurrent
> import Control.Concurrent.STM
> import System.IO
> import Control.Exception (finally)
>
> myFork :: IO () -> IO (MVar ())
> myFork a = do
> v <- newEmptyMVar
> a `finally` (putMVar v ())
> return v -- to honor the return type
>
> myWait :: MVar () -> IO ()
> myWait = readMVar
>
> main = do
> let fname = "store.txt"
> fh <- openFile fname ReadWriteMode
> store <- atomically $ newTMVar fh
> waitMes <- 10 `replicateM` (myFork $ writeTo store)
> mapM_ myWait waitMes
>
> writeTo :: TMVar (Handle) -> IO ()
> writeTo store = do
> fh <- atomically $ takeTMVar store
> text <- hGetContents fh
> hPutStr fh (text ++ " some text ")
> atomically $ putTMVar store fh
>
> Now I get the following error : test3: store.txt: hPutStr: illegal
> operation (handle is closed)
>
> reading the doc about hGetContents, I found that : "Computation
> hGetContents hdl returns the list of characters corresponding to the unread
> portion of the channel or file managed by hdl, which is put into an
> intermediate state, semi-closed. In this state, hdl is effectively closed"
>
>
> Intuitively I'd want to write something like
> : writeTo filename = atomically (do { s <- readFile filename ;
> writeFile filename (s ++ "blah") })
> but the type system prevents me from doing IO within STM
> I do not know how to go about sharing access to a file between multiple
> threads using STM... any pointers ?
>
> Thanks
>
> E.
>
>
>
>
>
>
>
>
>
> --
> Emmanuel Delaborde
> Web Technologist
> Cimex
> 53-55 Scrutton Street, London UK, EC2A 4PJ
> T: +44 (0)20 7324 7780
> F: +44 (0)20 7324 7781
> http://www.cimex.com
>
> -----------------------------------------------------------------------------------------------
>
> This e-mail (and any attachments) is confidential and may contain
> personal views which are not the views of Cimex Media Ltd and
> any affiliated companies, unless specifically stated. It is intended
> for the use of the individual or group to whom it is addressed. If
> you have received it in error, please delete it from your system,
> do not use, copy or disclose the information in any way nor act in
> reliance on it and please notify [email protected]
>
> A company registered in England Wales. Company Number 03765711
> Registered Office : The Olde Bakehouse, 156 Watling Street East, Towcester,
> Northants NN12 6DB
>
> This email was scanned by Postini, the leading provider in Managed Email
> Security.
>
>
>
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
http://www.haskell.org/pipermail/beginners/attachments/20090409/d8a52eba/attachment.htm
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 10, Issue 9
****************************************