Re: [Haskell-cafe] Behavior of -threaded in GHC 7.4.1?
Got this figured out, so I thought I'd update the list: The problem was a call to `addFinalizer` on a `Socket` value, where data Socket a = Socket { _socket :: Ptr () , _sockLive :: IORef Bool } Under 7.4.1 with -threaded, the finalizer was being run prematurely. I'm not clear on why, but the notes here [1] would suggest it's because the Socket type is optimized away. In any case, putting the finalizer on the inner Ptr () seems to have fixed the problem. Mike Craig On Wed, Feb 15, 2012 at 7:02 AM, Michael Craig mks...@gmail.com wrote: Ok, so I've found that using the -V0 RTS flag to turn off the RTS clock (and associated signals) makes the code run fine with -threaded. I'm still digging through the implications of that, though. Has some behavior here changed in 7.4.1? Mike Craig On Tue, Feb 14, 2012 at 3:54 PM, Michael Craig mks...@gmail.com wrote: Hi all, I'm debugging an issue with multithreading and FFI calls in 7.4.1. The code in question is the zeromq3-haskell library, which provides an FFI binding to ZeroMQ. A little background: ZeroMQ gives the programmer contexts and sockets. Contexts are thread-safe and generally used one-per-process, but sockets and not thread-safe so they're generally used one-per-thread. Have a look at the code in this gist: https://gist.github.com/1829190It's just a server that prints requests and replies with Hello, and a client that sends the requests [1, 2, ..., 10] and prints the responses. Despite the fact that ZMQ sockets are not thread-safe, it was possible to compile and run this code with -threaded under 7.0.4. Using MVars or some other locking mechanism, it was even possible to use the same socket from multiple parallel threads. (As long as the socket was not actually used in parallel by multiple threads, all was well.) In 7.4.1, the code will only run if compiled without -threaded. With -threaded, it croaks with an operation on non-socket error, which generally refers to a socket that's either been closed or I've dug through the code in zeromq3-haskell and haven't found anything suspicious looking. Before I go digging into libzmq itself, can somebody assure me that nothing has changed in 7.4.1 with regard to -threaded or the FFI that might cause this breakage? Cheers, Mike Craig ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Behavior of -threaded in GHC 7.4.1?
Ok, so I've found that using the -V0 RTS flag to turn off the RTS clock (and associated signals) makes the code run fine with -threaded. I'm still digging through the implications of that, though. Has some behavior here changed in 7.4.1? Mike Craig On Tue, Feb 14, 2012 at 3:54 PM, Michael Craig mks...@gmail.com wrote: Hi all, I'm debugging an issue with multithreading and FFI calls in 7.4.1. The code in question is the zeromq3-haskell library, which provides an FFI binding to ZeroMQ. A little background: ZeroMQ gives the programmer contexts and sockets. Contexts are thread-safe and generally used one-per-process, but sockets and not thread-safe so they're generally used one-per-thread. Have a look at the code in this gist: https://gist.github.com/1829190It's just a server that prints requests and replies with Hello, and a client that sends the requests [1, 2, ..., 10] and prints the responses. Despite the fact that ZMQ sockets are not thread-safe, it was possible to compile and run this code with -threaded under 7.0.4. Using MVars or some other locking mechanism, it was even possible to use the same socket from multiple parallel threads. (As long as the socket was not actually used in parallel by multiple threads, all was well.) In 7.4.1, the code will only run if compiled without -threaded. With -threaded, it croaks with an operation on non-socket error, which generally refers to a socket that's either been closed or I've dug through the code in zeromq3-haskell and haven't found anything suspicious looking. Before I go digging into libzmq itself, can somebody assure me that nothing has changed in 7.4.1 with regard to -threaded or the FFI that might cause this breakage? Cheers, Mike Craig ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Behavior of -threaded in GHC 7.4.1?
Hi all, I'm debugging an issue with multithreading and FFI calls in 7.4.1. The code in question is the zeromq3-haskell library, which provides an FFI binding to ZeroMQ. A little background: ZeroMQ gives the programmer contexts and sockets. Contexts are thread-safe and generally used one-per-process, but sockets and not thread-safe so they're generally used one-per-thread. Have a look at the code in this gist: https://gist.github.com/1829190 It's just a server that prints requests and replies with Hello, and a client that sends the requests [1, 2, ..., 10] and prints the responses. Despite the fact that ZMQ sockets are not thread-safe, it was possible to compile and run this code with -threaded under 7.0.4. Using MVars or some other locking mechanism, it was even possible to use the same socket from multiple parallel threads. (As long as the socket was not actually used in parallel by multiple threads, all was well.) In 7.4.1, the code will only run if compiled without -threaded. With -threaded, it croaks with an operation on non-socket error, which generally refers to a socket that's either been closed or I've dug through the code in zeromq3-haskell and haven't found anything suspicious looking. Before I go digging into libzmq itself, can somebody assure me that nothing has changed in 7.4.1 with regard to -threaded or the FFI that might cause this breakage? Cheers, Mike Craig ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] The State of Testing?
Thanks Thomas, that new flag is great. Mike Craig On Tue, Feb 7, 2012 at 10:03 PM, Thomas Tuegel ttue...@gmail.com wrote: On Tue, Feb 7, 2012 at 3:23 PM, Austin Seipp mad@gmail.com wrote: If you're writing a library, you need to compile the library with `-fhpc`, i.e. put it in the library stanza, not the testsuite stanza, and then you can compile the test program using your library - the resulting 'tix' file will contain the library coverage reports. You can link a HPC-built library into an executable not compiled with HPC just fine. Normally I only compile the library under HPC mode, link it in a test, and distribute the results from that. That way your coverage reports don't include the test module (which may or may not be relevant.) I normally add a cabal flag called 'hpc' which optionally enables coverage reports for my library, e.g. flag hpc default: False library ... ... if flag(hpc) ghc-options: -fhpc Then when you want coverage reports, just say 'cabal install -fhpc --enable-tests' and the resulting properties executable will spit out the results when run. First, as author of the test suite code, let me apologize for the terrible documentation. This is absolutely NOT how coverage reports are supposed to work. If you configure with '--enable-tests --enable-library-coverage', Cabal will take care of _everything_ else for you, including excluding the test module from the coverage report. You should not have to put any flag gymnastics in your .cabal file. If this doesn't work for you, please let me know, because it's a bug. Thanks! -- Thomas Tuegel ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] The State of Testing?
Thanks for the advice, all. I've got test-framework, quickcheck, and cabal's test-suite all working together nicely. Cabal seems to support using hpc to check test coverage. If I add -fhpc to the ghc-options under the test-suite, I get output like Test coverage report written to dist/hpc/html/tests/hpc_index.html and Package coverage report written to dist/hpc/html/test-0.0.0/hpc_index.html, but those html files are just empty tables. How does this work? Mike Craig On Thu, Feb 2, 2012 at 8:45 PM, Ivan Lazar Miljenovic ivan.miljeno...@gmail.com wrote: On 03/02/2012 12:22 PM, Johan Tibell johan.tib...@gmail.com wrote: On Thu, Feb 2, 2012 at 4:46 PM, Conrad Parker con...@metadecks.org wrote: On 3 February 2012 08:30, Johan Tibell johan.tib...@gmail.com wrote: On Thu, Feb 2, 2012 at 4:19 PM, Conrad Parker con...@metadecks.org wrote: I've followed what Johan Tibbell did in the hashable package: If I had known how much confusion my childhood friends would unleash on the Internet when they, at age 7, gave me a nickname that's spelled slightly differently from my last name, I would have asked them to pick another one. ;) lol, sorry, I actually double-checked the number of l's before writing that but didn't consider the b's. For future reference I've produced a handy chart: Letter | Real-name count | Nickname count ---+-+--- b | 1 | 2 l | 2 | 0 ---+-+--- SUM| 3 | 2 Excellent. I will tattoo it on my forehead. There is, of course, a simpler (but not necessarily easier :p) solution: change your name to match your nickname! ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] The State of Testing?
How do you control where the .mix files are generated? GHC is putting them in .hpc/, but I'm getting errors like hpc: can not find test-0.0.0/Data.Test in [./dist/hpc/mix/test-0.0.0]. Mike Craig On Tue, Feb 7, 2012 at 5:12 PM, Ryan Newton rrnew...@gmail.com wrote: By the way, has anyone else had trouble with cabal test diverging? I've been running into this issue with cabal 0.10.2, but ONLY in conjunction with GHC 6.12.3. It's hard to make a small reproducer for (and therefore I haven't filed a bug yet), but you can see the below Jenkins run stalled for 2.5 days, whereas it should take minutes: http://tester-lin.soic.indiana.edu:8080/job/monad-par_github_master/JENKINS_GHC=ghc-6.12.3/17/console Note that it *doesn't* burn CPU -- it deadlocks rather than spins. I replaced cabal test with a direct call to the test executable and I haven't seen this problem since. -Ryan On Tue, Feb 7, 2012 at 4:23 PM, Austin Seipp mad@gmail.com wrote: If you're writing a library, you need to compile the library with `-fhpc`, i.e. put it in the library stanza, not the testsuite stanza, and then you can compile the test program using your library - the resulting 'tix' file will contain the library coverage reports. You can link a HPC-built library into an executable not compiled with HPC just fine. Normally I only compile the library under HPC mode, link it in a test, and distribute the results from that. That way your coverage reports don't include the test module (which may or may not be relevant.) I normally add a cabal flag called 'hpc' which optionally enables coverage reports for my library, e.g. flag hpc default: False library ... ... if flag(hpc) ghc-options: -fhpc Then when you want coverage reports, just say 'cabal install -fhpc --enable-tests' and the resulting properties executable will spit out the results when run. On Tue, Feb 7, 2012 at 3:16 PM, Michael Craig mks...@gmail.com wrote: Thanks for the advice, all. I've got test-framework, quickcheck, and cabal's test-suite all working together nicely. Cabal seems to support using hpc to check test coverage. If I add -fhpc to the ghc-options under the test-suite, I get output like Test coverage report written to dist/hpc/html/tests/hpc_index.html and Package coverage report written to dist/hpc/html/test-0.0.0/hpc_index.html, but those html files are just empty tables. How does this work? Mike Craig On Thu, Feb 2, 2012 at 8:45 PM, Ivan Lazar Miljenovic ivan.miljeno...@gmail.com wrote: On 03/02/2012 12:22 PM, Johan Tibell johan.tib...@gmail.com wrote: On Thu, Feb 2, 2012 at 4:46 PM, Conrad Parker con...@metadecks.org wrote: On 3 February 2012 08:30, Johan Tibell johan.tib...@gmail.com wrote: On Thu, Feb 2, 2012 at 4:19 PM, Conrad Parker con...@metadecks.org wrote: I've followed what Johan Tibbell did in the hashable package: If I had known how much confusion my childhood friends would unleash on the Internet when they, at age 7, gave me a nickname that's spelled slightly differently from my last name, I would have asked them to pick another one. ;) lol, sorry, I actually double-checked the number of l's before writing that but didn't consider the b's. For future reference I've produced a handy chart: Letter | Real-name count | Nickname count ---+-+--- b | 1 | 2 l | 2 | 0 ---+-+--- SUM| 3 | 2 Excellent. I will tattoo it on my forehead. There is, of course, a simpler (but not necessarily easier :p) solution: change your name to match your nickname! ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe -- Regards, Austin ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] The State of Testing?
I've been picking up Haskell as a side project for the last few months, and I'm now considering publishing some useful code I've written and reused in several small projects. So far I've done relatively little with testing (these have been non-mission-critical applications) but I feel I should get my act together before pushing my work into the common ecosystem. I'm comfortable writing tests in QuickCheck and HUnit and bundling them as optional executables with cabal, but I understand there's a better way. Specifically, I'm looking at the test-framework package and cabal's (newish) test-suite sections. Are these two used together or each to the exclusion of the other? Is there something else I should be using? Cheers, Mike Craig ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] named pipe interface
Brandon, can you elaborate? Are you talking about UNIX named pipes or FIFO/queue data structures in general? Mike Craig On Fri, Jan 13, 2012 at 12:39 PM, Brandon Allbery allber...@gmail.comwrote: On Fri, Jan 13, 2012 at 12:25, Serge D. Mechveliani mech...@botik.ruwrote: On Fri, Jan 13, 2012 at 04:34:37PM +0100, Chadda?? Fouch?? wrote: Now that seems interesting, but just to be clear : did you choose this solution (and why won't you use the FFI instead) or is this just to see how to work it out ? Because it is a direct and the simplest approach. Why does one need a foreign language, if all the needed functions are in the standard Haskell library? I hope you are aware of the many gotchas involved with FIFOs. There are very good reasons why they are not widely used. -- brandon s allbery allber...@gmail.com wandering unix systems administrator (available) (412) 475-9364 vm/sms ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Composing Enumeratees in enumerator
I wound up emailing John Millikin about this and he made a good case against these kinds of simplified operators, which is basically the problem of handling left-over input. The joinI and joinE combinators discard the left-over Stream that is yielded by the inner iteratee. (As John explains it, this is a trade-off between ease of use and programming complexity.) Simplified operators (like $=, =$, and now =$=) use repeated joinI's, so left-over input may be lost in various places. When using simple iteratees that never yield left-over input, this isn't a problem and the operators make sense. For more complex pipelines, John advocates a style like this: joinI (foo $$ (bar $$ baz)) so that left over data is only discarded once after the computation is otherwise complete. In any case, there's now a new release of enumerator (0.4.17) which includes an enumeratee composition operator: (=$=) :: Monad m = Enumeratee a1 a2 m (Step a3 m b) - Enumeratee a2 a3 m b - Enumeratee a1 a3 m b. Cheers, Mike Craig On Tue, Dec 27, 2011 at 10:12 AM, Michael Craig mks...@gmail.com wrote: Thanks for the replies, all. It's good to see that the other iteratee packages out there are addressing this issue. I still don't get why it's an issue in the first place. It seems to me like a pretty simple thing to implement: (=$=) :: (Monad m) = Enumeratee a0 a1 m (Step a2 m b) - Enumeratee a1 a2 m b - Enumeratee a0 a2 m b (=$=) e01 e12 step = Iteratee $ do step' - runIteratee $ e12 step runIteratee . joinI $ e01 step' This puts a type restriction on the LHS enumeratee, but enumeratees are generally polymorphic in the last type param anyway. (And joinE has a similar restriction when composing an enumerator with an enumeratee.) Is there a good reason why enumerator doesn't export this or something analogous? Mike Craig On Sun, Dec 25, 2011 at 10:20 PM, Conrad Parker con...@metadecks.orgwrote: On 24 December 2011 05:47, Michael Craig mks...@gmail.com wrote: I've been looking for a way to compose enumeratees in the enumerator package, but I've come up with nothing so far. I want this function (=$=) :: Monad m = Enumeratee a0 a1 m b - Enumeratee a1 a2 m b - Enumeratee a0 a2 m b I'm building a modular library on top of enumerator that facilitates reading time series data from a DB, applying any number of transformations to it, and then writing it back / doing something else with it. I'd like to be able to write simple transformations (enumeratees) and compose them without binding them to either a db reader (enumerator) or db writer (iteratee). I've been looking at the iterIO package as a possible alternative, because it seems to allow easy composition of Inums (enumeratees). I'm a little skittish of it because it seems unpopular next to enumerator. Hi Michael, You could also look at the iteratee package. This is the signature of the () operator: () :: (Nullable s1, Monad m) = (forall x. Enumeratee s1 s2 m x) - Enumeratee s2 s3 m a - Enumeratee s1 s3 m a it's quite useful for composing enumeratees, likewise its friend () swims the other way. http://hackage.haskell.org/packages/archive/iteratee/0.8.7.5/doc/html/Data-Iteratee-Iteratee.html cheers, Conrad. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Composing Enumeratees in enumerator
Thanks for the replies, all. It's good to see that the other iteratee packages out there are addressing this issue. I still don't get why it's an issue in the first place. It seems to me like a pretty simple thing to implement: (=$=) :: (Monad m) = Enumeratee a0 a1 m (Step a2 m b) - Enumeratee a1 a2 m b - Enumeratee a0 a2 m b (=$=) e01 e12 step = Iteratee $ do step' - runIteratee $ e12 step runIteratee . joinI $ e01 step' This puts a type restriction on the LHS enumeratee, but enumeratees are generally polymorphic in the last type param anyway. (And joinE has a similar restriction when composing an enumerator with an enumeratee.) Is there a good reason why enumerator doesn't export this or something analogous? Mike Craig On Sun, Dec 25, 2011 at 10:20 PM, Conrad Parker con...@metadecks.orgwrote: On 24 December 2011 05:47, Michael Craig mks...@gmail.com wrote: I've been looking for a way to compose enumeratees in the enumerator package, but I've come up with nothing so far. I want this function (=$=) :: Monad m = Enumeratee a0 a1 m b - Enumeratee a1 a2 m b - Enumeratee a0 a2 m b I'm building a modular library on top of enumerator that facilitates reading time series data from a DB, applying any number of transformations to it, and then writing it back / doing something else with it. I'd like to be able to write simple transformations (enumeratees) and compose them without binding them to either a db reader (enumerator) or db writer (iteratee). I've been looking at the iterIO package as a possible alternative, because it seems to allow easy composition of Inums (enumeratees). I'm a little skittish of it because it seems unpopular next to enumerator. Hi Michael, You could also look at the iteratee package. This is the signature of the () operator: () :: (Nullable s1, Monad m) = (forall x. Enumeratee s1 s2 m x) - Enumeratee s2 s3 m a - Enumeratee s1 s3 m a it's quite useful for composing enumeratees, likewise its friend () swims the other way. http://hackage.haskell.org/packages/archive/iteratee/0.8.7.5/doc/html/Data-Iteratee-Iteratee.html cheers, Conrad. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Composing Enumeratees in enumerator
I've been looking for a way to compose enumeratees in the enumerator package, but I've come up with nothing so far. I want this function (=$=) :: Monad m = Enumeratee a0 a1 m b - Enumeratee a1 a2 m b - Enumeratee a0 a2 m b I'm building a modular library on top of enumerator that facilitates reading time series data from a DB, applying any number of transformations to it, and then writing it back / doing something else with it. I'd like to be able to write simple transformations (enumeratees) and compose them without binding them to either a db reader (enumerator) or db writer (iteratee). I've been looking at the iterIO package as a possible alternative, because it seems to allow easy composition of Inums (enumeratees). I'm a little skittish of it because it seems unpopular next to enumerator. Thoughts on these issues? Cheers, Mike S Craig ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Module name space question
There is, and it's awesome: http://folk.ntnu.no/hammar/**explore-hackage/http://folk.ntnu.no/hammar/explore-hackage/ Though it can be a bit slow to load, so try not to hammer the server too hard :) Awesome indeed! Can we convince Andreas to have it update regularly? Looks like the last update was in May. Mike S Craig On Mon, Dec 12, 2011 at 3:45 PM, wren ng thornton w...@freegeek.org wrote: On 12/12/11 9:32 AM, Ryan Newton wrote: I don't know why Hoogle didn't find one of the packages. I've often wondered about this related question: * Is there a place to browse the union of all namespaces in all hackage packages? There is, and it's awesome: http://folk.ntnu.no/hammar/**explore-hackage/http://folk.ntnu.no/hammar/explore-hackage/ Though it can be a bit slow to load, so try not to hammer the server too hard :) -- Live well, ~wren __**_ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/**mailman/listinfo/haskell-cafehttp://www.haskell.org/mailman/listinfo/haskell-cafe ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Attoparsec: Limiting Parsers to N Bytes, or Combing Parsers?
Suppose we want to parse a 24-bit hex color value: input :: ByteString input = af093c blah blah blah type Color = (Word8, Word8, Word8) Attoparsec.Char8 exports a nice hexadecimal parser, but it consumes all available hex-flavored input. I'd like to make it consume exactly two bytes, so I could write my color parser like this: color :: Parser Color color = do r - hex2 g - hex2 b - hex2 return $ Color (r, g, b) hex2 :: Parser Word8 hex2 = ??? So my question is how do I write hex2? I could easily rewrite hexadecimal, but it would be nicer to reuse its hex-handling logic. Best, Mike S Craig (908) 328 8030 ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Attoparsec: Limiting Parsers to N Bytes, or Combing Parsers?
I agree on all counts! The hex-handling logic here is so straightforward that it's hardly worth bothering with. In fact, my application's code as it stands looks very similar to what you wrote. I'm really asking because I want to be more fluent in attoparsec. So the question remains: is there a way to limit a parser to a finite chunk of input? Perhaps a way to run the 'take n' parser on the input and then run another parser on its result? This smells like monadic behavior, but of course with different semantics than the Monad instance for Parser. Mike S Craig (908) 328 8030 On Fri, Sep 23, 2011 at 11:23 PM, Evan Laforge qdun...@gmail.com wrote: BTW you probably want 'data Color = Color !Word8 !Word8 !Word8' On Fri, Sep 23, 2011 at 8:21 PM, Evan Laforge qdun...@gmail.com wrote: On Fri, Sep 23, 2011 at 8:04 PM, Michael Craig mks...@gmail.com wrote: Suppose we want to parse a 24-bit hex color value: input :: ByteString input = af093c blah blah blah type Color = (Word8, Word8, Word8) Attoparsec.Char8 exports a nice hexadecimal parser, but it consumes all available hex-flavored input. I'd like to make it consume exactly two bytes, so I could write my color parser like this: color :: Parser Color color = do r - hex2 g - hex2 b - hex2 return $ Color (r, g, b) hex2 :: Parser Word8 hex2 = ??? So my question is how do I write hex2? I could easily rewrite hexadecimal, but it would be nicer to reuse its hex-handling logic. If it's easy enough to write inline, might as well do so. And it's fun with Applicative :) hex2 = (+) $ ((*16) $ higit) * higit higit = subtract (fromEnum '0') $ satisfy isHexDigit color = Color $ hex2 * hex2 * hex2 ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe