Re: [Haskell-cafe] ANN: generic-deepseq 1.0.0.0
On Sat, 2012-02-25 at 11:38 +0100, José Pedro Magalhães wrote: 2012/2/25 Andres Löh andres.l...@googlemail.com Would you have an example of a type for which it would be useful to have a DeepSeq instance, and that would require a V1 instance? I cannot think of one now; I originaly thought it would be necessary to permit deriving DeepSeq instances for types tagged with void types, but as José explained, in that case, the V1 instance isn't needed because those void types don't show up in the representation. While void datatypes are rare, it just doesn't make sense to exclude them. It's an arbitrary restriction. Here's a constructed example: data X a = C1 Int | C2 a data Z -- empty type Example = X Z We're using Z as a parameter to X in order to exclude the use of the C2 case. Without a V1 case, you cannot use deepSeq on values of type Example. Yes, I agree. There should be a V1 instance, and it should return `undefined`. This gives the expected behavior of `seq` on an empty datatype, I think. If there is no V1 instance, you'll get a type-checking error (no instance for V1), preventing generic deepseq on any datatype that happens to use an empty datatype in its definition. Thanks for all the input guys. I have just released generic-deepseq 2.0.1.0 to hackage, with fixed U1 and V1 instances per this discussion. Cheers, Maxime signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ANN: generic-deepseq 1.0.0.0
On Fri, 2012-02-24 at 07:49 +0100, Jos Pedro Magalhes wrote: Hi, 2012/2/23 Maxime Henrion mhenr...@gmail.com * Why do you have the instance: instance GDeepSeq V1 where grnf _ = () The only way to construct values of a void type is using ⊥. And I would expect that rnf ⊥ = ⊥, not (). I think the best thing is to just remove the V1 instance. This would have the consequence that any type tagged with a phantom type (for whatever reason) couldn't be used with deepseq, it would return bottom. What if I want to deepseq a 2-3 finger tree tagged with a type-level natural that ensures the proper shape of the tree statically? It seemed to me that I should be able to do that; this is why I added this V1 instance. I'm not sure I understand your comment... V1 should only be used for datatypes without constructors, such as `data Empty`. Yes, such as the usual type-level naturals (not using DataKinds): data Z data S n Those can be used to tag a type which also contains actual values that you would want to deepseq? For example, a length-type vector? I seemed to remember a similar construct for 2-3 finger trees that would statically guarantee that the shape of the tree is valid, so I took that as an example, but I don't remember the specifics. Cheers, Maxime signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ANN: generic-deepseq 1.0.0.0
On Fri, 2012-02-24 at 09:32 +0100, Jos Pedro Magalhes wrote: 2012/2/24 Maxime Henrion mhenr...@gmail.com On Fri, 2012-02-24 at 07:49 +0100, Jos Pedro Magalhes wrote: Hi, 2012/2/23 Maxime Henrion mhenr...@gmail.com * Why do you have the instance: instance GDeepSeq V1 where grnf _ = () The only way to construct values of a void type is using ⊥. And I would expect that rnf ⊥ = ⊥, not (). I think the best thing is to just remove the V1 instance. This would have the consequence that any type tagged with a phantom type (for whatever reason) couldn't be used with deepseq, it would return bottom. What if I want to deepseq a 2-3 finger tree tagged with a type-level natural that ensures the proper shape of the tree statically? It seemed to me that I should be able to do that; this is why I added this V1 instance. I'm not sure I understand your comment... V1 should only be used for datatypes without constructors, such as `data Empty`. Yes, such as the usual type-level naturals (not using DataKinds): data Z data S n Those can be used to tag a type which also contains actual values that you would want to deepseq? For example, a length-type vector? But in those cases they are used as tags, not as values, and hence do not show up in the generic representation. So if all you want is to be able to deepseq a value of a type like data Proxy t = Proxy even if your value is of type `Proxy Ze`, you shouldn't need a `V1` instance. Oh, ok; in that case, I probably don't need that V1 instance indeed. I should probably write QuickCheck tests using the ChasingBottoms package in order to ensure correct behaviour of this code. Thanks, Maxime signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ANN: generic-deepseq 1.0.0.0
On Fri, 2012-02-24 at 15:28 +0100, Andres Löh wrote: Hi. I don't understand what's going on here. Instances for V1 should of course be defined if they can be! And in this case, a V1 instance makes sense and should be defined. The definition itself doesn't matter, as it'll never be executed. The definition certainly matters: [...] You're right. I was too quick to conclude the definition doesn't matter. But it should still be there. V1 can occur in representations of non-empty types (even if the current mechanism might not generate them). You'd still want to be able to call generic functions on such types. Would you have an example of a type for which it would be useful to have a DeepSeq instance, and that would require a V1 instance? I cannot think of one now; I originaly thought it would be necessary to permit deriving DeepSeq instances for types tagged with void types, but as José explained, in that case, the V1 instance isn't needed because those void types don't show up in the representation. Cheers, Maxime signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ANN: generic-deepseq 1.0.0.0
On Thu, 2012-02-23 at 23:24 +0100, Bas van Dijk wrote: Some nitpicking: * In the instance: instance GDeepSeq U1 where grnf _ = () I think it makes sense to pattern match on the U1 constructor, as in: grnf U1 = (). I haven't checked if that's necessary but my fear is that assuming: data Unit = Unit deriving Generic; instance DeepSeq Unit rnf (⊥ :: Unit) would equal: () while I would expect it to equal ⊥. I just tested this and you were right; I have corrected the code in the mercurial repository. * Why do you have the instance: instance GDeepSeq V1 where grnf _ = () The only way to construct values of a void type is using ⊥. And I would expect that rnf ⊥ = ⊥, not (). I think the best thing is to just remove the V1 instance. I have confirmed what Jos explained, and V1 instances are indeed not necessary for the use case I originally intended them for, that is for types tagged with void types. I have removed the V1 instance for now. Thanks, Maxime signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ANN: generic-deepseq 1.0.0.0
On Thu, 2012-02-23 at 23:24 +0100, Bas van Dijk wrote: On 23 February 2012 22:09, Maxime Henrion mhenr...@gmail.com wrote: On Sun, 2012-02-19 at 21:06 +0100, Bas van Dijk wrote: On 19 February 2012 18:11, Maxime Henrion mhenr...@gmail.com wrote: I'm guilty of not having preserved the rnf :: a - () function as the class function though, it's a wrapper around deepseq in my code. I just didn't see the point of having a class function with such a signature versus having a function just like seq :: a - b - b. In retrospect, that might have been a bad idea, and maybe I should switch to have an rnf :: a - () class function to make switching even easier? I'm not sure but maybe a method like rnf :: a - () is easier to optimize. Also in my experience (with generics support in aeson and cereal) it's a very good idea (performance-wise) to INLINE your methods like I did in my previous message. Of course the only way to know for sure is the create some (criterion) benchmarks. Well I wrote some dumb criterion benchmarks that run deepseq over increasingly bigger lists of numbers, and it appears that using rnf as the member function of the DeepSeq class indeed makes a _huge_ difference. Nice, that's what I expected. Have you checked if adding INLINE pragma's helps even more? (I guess not since it's already on par with manual written code, as you mentioned) Oh, I had forgotten to mention that: INLINE pragmas indeed didn't make any significant difference in my tests, so I let them out. BTW I would also recommend making a benchmark for a big sum type. Yes, I should definitely do that. Some nitpicking: * In the instance: instance GDeepSeq U1 where grnf _ = () I think it makes sense to pattern match on the U1 constructor, as in: grnf U1 = (). I haven't checked if that's necessary but my fear is that assuming: data Unit = Unit deriving Generic; instance DeepSeq Unit rnf (⊥ :: Unit) would equal: () while I would expect it to equal ⊥. That's a good point, I will do tests to see whether this makes a difference. This seems to mirror my thinking when I asked you whether it would be safe to skip seq calls in the case the constructor of a type is strict in another e-mail (have you seen it?). * Why do you have the instance: instance GDeepSeq V1 where grnf _ = () The only way to construct values of a void type is using ⊥. And I would expect that rnf ⊥ = ⊥, not (). I think the best thing is to just remove the V1 instance. This would have the consequence that any type tagged with a phantom type (for whatever reason) couldn't be used with deepseq, it would return bottom. What if I want to deepseq a 2-3 finger tree tagged with a type-level natural that ensures the proper shape of the tree statically? It seemed to me that I should be able to do that; this is why I added this V1 instance. Cheers, Maxime signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ANN: generic-deepseq 1.0.0.0
On Thu, 2012-02-23 at 23:45 +0100, Maxime Henrion wrote: On Thu, 2012-02-23 at 23:24 +0100, Bas van Dijk wrote: * Why do you have the instance: instance GDeepSeq V1 where grnf _ = () The only way to construct values of a void type is using ⊥. And I would expect that rnf ⊥ = ⊥, not (). I think the best thing is to just remove the V1 instance. This would have the consequence that any type tagged with a phantom type (for whatever reason) couldn't be used with deepseq, it would return bottom. Sorry, I had myself confused; it wouldn't return bottom, there would just be no way to get an instance for it (the rest of the argument still holds). signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] ANN: generic-deepseq 1.0.0.0
Hello all, Yesterday I uploaded a new package on Hackage called generic-deepseq. It implements the 'deepseq' function generically using the new GHC.Generics framework as found in GHC = 7.2. It can be used as a replacement for the deepseq package. Given that hackage is currently down, here is an URL from a mirror where the package description documentation can be found: http://hackage.factisresearch.com/package/generic-deepseq-1.0.0.0 Any suggestions are welcome. Cheers, Maxime Henrion signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ANN: generic-deepseq 1.0.0.0
On Sun, 2012-02-19 at 16:17 +0100, Bas van Dijk wrote: On 19 February 2012 13:12, Maxime Henrion mhenr...@gmail.com wrote: Any suggestions are welcome. Nice work but it would be nice to have this functionality directly in the deepseq package as in: #ifdef GENERICS {-# LANGUAGE DefaultSignatures, TypeOperators, FlexibleContexts #-} #endif class NFData a where rnf :: a - () rnf a = a `seq` () #ifdef GENERICS default rnf :: (Generic a, GNFData (Rep a)) = a - () rnf = grnf . from class GNFData f where grnf :: f a - () instance GNFData U1 where grnf U1 = () {-# INLINE grnf #-} instance NFData a = GNFData (K1 i a) where grnf = rnf . unK1 {-# INLINE grnf #-} instance GNFData f = GNFData (M1 i c f) where grnf = grnf . unM1 {-# INLINE grnf #-} instance (GNFData f, GNFData g) = GNFData (f :+: g) where grnf (L1 x) = grnf x grnf (R1 x) = grnf x {-# INLINE grnf #-} instance (GNFData f, GNFData g) = GNFData (f :*: g) where grnf (x :*: y) = grnf x `seq` grnf y {-# INLINE grnf #-} #endif Unfortunately this is not possible since the two default implementations conflict. I see two solutions: 1) Change the DefaultSignatures extension to always give preference to the default signature. I think giving preference to the default signature makes sense since it's usually more specific (more constraint) and thus more correct than the default implementation. 2) Remove the default implementation of rnf. I understand the default implementation gives some convenience when writing instances for types that have an all strict representation, as in: instance NFData Int instance NFData Word instance NFData Integer ... However, I think having the default implementation can mask some bugs as in: data T = C Int; instance NFData T which will neither give a compile time error nor warning. I don't think it's that much more inconvenient to write: instance NFData Int where rnf = rnf' instance NFData Word where rnf = rnf' instance NFData Integer where rnf = rnf' ... where rnf' :: a - () rnf' a = a `seq` () So I would vote for option 2, removing the default rnf implementation. If I find some time I will turn this into an official proposal. I agree it would have been nice to have that functionality directly in the deepseq package, or at least in a way that extends the existing functionality rather than completely replace it. However, as you noted, it isn't possible to do that in a backwards compatible way, unless we hack the implementation of the DefaultSignatures extension. That being said, even if it was possible to do this in a backwards compatible way, I'm not entirely sure it would be desirable to do so because there is one subtle difference between this code and the deepseq package. With the generic-deepseq package, you should only need to provide an explicit DeepSeq instance for some type if it is abstract, because you can't get a Generic instance in that case (unless the library author derived Generic himself, but that would be a weird and dangerous thing to do for an abstract datatype). If you're not dealing with an abstract datatype, you _shouldn't_ have an explicit instance, because it would be possible to write an incorrect one, while that is impossible if you just derive a generic implementation (as long as the generic code is correct, of course). So, knowing that it would necessarily be backwards incompatible (I wasn't intending to hack on GHC :-), and also that, in the end, this is not quite the same class as the NFData class from the deepseq package, I thought it made more sense to create another package that would be mostly compatible with deepseq, but with a different class name so as to force people to reevaluate the need for their instances if they have some. I'd be interested in knowing what you and others think about that. Maybe I'm being overly cautious? I kept the rest of the API identical so that it's still easy to switch to this package, thus you can still use the ($!!), force, and rnf functions. I'm guilty of not having preserved the rnf :: a - () function as the class function though, it's a wrapper around deepseq in my code. I just didn't see the point of having a class function with such a signature versus having a function just like seq :: a - b - b. In retrospect, that might have been a bad idea, and maybe I should switch to have an rnf :: a - () class function to make switching even easier? Thanks a lot for your input! Maxime Henrion signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ANN: generic-deepseq 1.0.0.0
On Sun, 2012-02-19 at 21:06 +0100, Bas van Dijk wrote: On 19 February 2012 18:11, Maxime Henrion mhenr...@gmail.com wrote: If you're not dealing with an abstract datatype, you _shouldn't_ have an explicit instance, because it would be possible to write an incorrect one, while that is impossible if you just derive a generic implementation (as long as the generic code is correct, of course). I agree. I hadn't considered this advantage yet. I guess it's the same argument for why it's better to automatically derive Data and Typeable instances using the DeriveDataTypeable extension. So, knowing that it would necessarily be backwards incompatible (I wasn't intending to hack on GHC :-), and also that, in the end, this is not quite the same class as the NFData class from the deepseq package, I thought it made more sense to create another package that would be mostly compatible with deepseq, but with a different class name so as to force people to reevaluate the need for their instances if they have some. I'd be interested in knowing what you and others think about that. Maybe I'm being overly cautious? I do think it's better to integrate this into the deepseq package (and thus removing the default implementation of rnf). Otherwise we end up with two ways of evaluating values to normal form. I'm okay with that, but I was interested in knowing whether you think my reasoning for changing the class name and thus deliberately breaking the API slightly more was sane or not (I say more because removing the default implementation of rnf already constitutes an API breakage in that the generic replacement would be optional and depends on having Generic instances to work). I'm guilty of not having preserved the rnf :: a - () function as the class function though, it's a wrapper around deepseq in my code. I just didn't see the point of having a class function with such a signature versus having a function just like seq :: a - b - b. In retrospect, that might have been a bad idea, and maybe I should switch to have an rnf :: a - () class function to make switching even easier? I'm not sure but maybe a method like rnf :: a - () is easier to optimize. Also in my experience (with generics support in aeson and cereal) it's a very good idea (performance-wise) to INLINE your methods like I did in my previous message. Of course the only way to know for sure is the create some (criterion) benchmarks. Yeah, I should definitely get going on the benchmarks. One last issue: Say I have a type like: data T = C !Int Currently GHC Generics can't express the strictness annotation. This means that your deepseq will unnecessarily evaluate the Int (since it will always be evaluated already). It would be nice if the strictness information could be added to the K1 type. (José, would it be hard to add this to GHC.Generics?) Assuming there is way to differentiate strict constructors in GHC.Generics, and that I have a specific instance so as to not call seq in that case, can you actually do such an optimization safely? Consider this code (imports omitted for simplicity): data T = C !Int deriving Generic instance DeepSeq T x :: T x = undefined main :: IO () main = print (x `deepseq` ()) I would expect this to diverge, just like it does if one uses `seq`. If we implement the optimization you suggest, I believe that deepseq wouldn't diverge, but I admit I'm not 100% sure either. Cheers, Maxime Henrion signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] DFAs and self-referential data
Hello all, I've been playing with some code to work with DFAs, but I'm now faced with an implementation problem. In order to have states that can transition to themselves, it seems I would need self-referential data; otherwise I would need to separate those transitions from the rest and handle them specially in the code. I tried to exploit laziness in order to get self-referential data as shown in the 'self' function below: module DFA where import Data.Map (Map) import qualified Data.Map as M data DFA a = DFA (Map a (DFA a)) -- The set of transitions functions Bool-- Is this a final state? accept :: Ord a = DFA a - [a] - Bool accept (DFA _ f) [] = f accept (DFA ts f) (x:xs) = maybe False (`accept` xs) (M.lookup x ts) empty :: Bool - DFA a empty = DFA M.empty path :: Ord a = a - DFA a - DFA a - DFA a path x d' (DFA ts f) = DFA (M.insert x d' ts) f self :: Ord a = a - DFA a - DFA a self x d = let d' = path x d' d in d' test :: String - Bool test = accept s1 where s1 = path '0' s2 . self '1' $ empty True s2 = path '0' s1 . self '1' $ empty False The automaton I construct in the 'test' function is the example one from the wikipedia page (http://en.wikipedia.org/wiki/Deterministic_finite_automaton) on DFAs. It should accept any string formed with ones and zeros that contain an even number of zeros (or, equivalently, strings that match the regular expression 1*(0(1*)0(1*))*). Unfortunately, this doesn't seem to give the desired effect: *DFA test 0 False *DFA test 00 True *DFA test 000 False *DFA test True *DFA test 1 True *DFA test 11 True *DFA test 111 True *DFA test 11100 False Anyone knows what I'm doing wrong here? I suspect my attempt at having self-referential data is somehow buggy; do I need to treat transitions to the same state differently? Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] DFAs and self-referential data
On Sun, 2010-12-26 at 13:58 +0200, Roman Cheplyaka wrote: * Maxime Henrion mhenr...@gmail.com [2010-12-26 12:01:31+0100] Anyone knows what I'm doing wrong here? I suspect my attempt at having self-referential data is somehow buggy; do I need to treat transitions to the same state differently? The problem is that when you call 'self', you record *that* state of your DFA in the map. When DFA gets updated further, the recorded self-reference is not updated appropriately. In your case a workaround is to call 'self' after all the other updates, i.e. test :: String - Bool test = accept s1 where s1 = self '1' . path '0' s2 $ empty True s2 = self '1' . path '0' s1 $ empty False But I don't see why you need 'self' at all -- you can just use path as with any other type of transition: test :: String - Bool test = accept s1 where s1 = path '0' s2 . path '1' s1 $ empty True s2 = path '0' s1 . path '1' s2 $ empty False Indeed this just works, thanks! The reason I was using a 'self' function was that I initially thought it would be more convenient; I now see it doesn't, especially considering it doesn't even work. However I'm a bit confused as to why things just work without having to reorder the calls when using the 'path' function - my brain seems to have difficulties following the code path here :-). Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] DFAs and self-referential data
On Sun, 2010-12-26 at 13:38 +0100, Maxime Henrion wrote: On Sun, 2010-12-26 at 13:58 +0200, Roman Cheplyaka wrote: * Maxime Henrion mhenr...@gmail.com [2010-12-26 12:01:31+0100] Anyone knows what I'm doing wrong here? I suspect my attempt at having self-referential data is somehow buggy; do I need to treat transitions to the same state differently? The problem is that when you call 'self', you record *that* state of your DFA in the map. When DFA gets updated further, the recorded self-reference is not updated appropriately. In your case a workaround is to call 'self' after all the other updates, i.e. test :: String - Bool test = accept s1 where s1 = self '1' . path '0' s2 $ empty True s2 = self '1' . path '0' s1 $ empty False But I don't see why you need 'self' at all -- you can just use path as with any other type of transition: test :: String - Bool test = accept s1 where s1 = path '0' s2 . path '1' s1 $ empty True s2 = path '0' s1 . path '1' s2 $ empty False Indeed this just works, thanks! The reason I was using a 'self' function was that I initially thought it would be more convenient; I now see it doesn't, especially considering it doesn't even work. However I'm a bit confused as to why things just work without having to reorder the calls when using the 'path' function - my brain seems to have difficulties following the code path here :-). Oh, nevermind, I finally figured it out. When using my 'self' function, as you said, I point at the version of the DFA I have when calling 'self', and not the final version of the DFA after other calls to 'path'. So as soon as I was following a self transition, I was ending up with an 'old' version of the DFA. Whereas in your version, the binding I point to is the final DFA version. Thanks a lot! Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Defining a CPP macro when building documentation
Hello all, I have been exposed to a problem that have happened to others too, and since I have found a (scary) solution with the help of Duncan Coutts, I'm now sharing it with you. The reason I wanted to pass specific CPP flags to haddock was to allow the documentation of the full module to get built, even when only parts of the module would end up getting compiled because of restrictions on the build platform. In this mail, Duncan Coutts gives a very helpful bit of code to override the haddockHook and pass additional options to haddock : http://www.haskell.org/pipermail/haskell-cafe/2008-December/051785.html In my case, I needed something very similar, except that I needed to pass those additional options to hsc2hs which my code uses. This worked fine as long as the cabal commands sequence was [configure,haddock] and not [configure,build,haddock]. The reason for this is that in the latter case, the library wasn't being processed again, but output of previous runs of hsc2hs were reused. So I worked around this with an ugly hack that removes the .hs files before running haddock, in order to force re-processing! Here's the final code I ended up with : import Distribution.Simple import Distribution.Simple.LocalBuildInfo (LocalBuildInfo(withPrograms), buildDir) import Distribution.Simple.Program (userSpecifyArgs) import System.Directory import System.FilePath -- Define __HADDOCK__ when building documentation. main = defaultMainWithHooks simpleUserHooks { haddockHook = \pkg lbi h f - do let progs = userSpecifyArgs hsc2hs [-D__HADDOCK__] (withPrograms lbi) removePreProcessedFiles (buildDir lbi) haddockHook simpleUserHooks pkg lbi { withPrograms = progs } h f } -- Horrible hack to force re-processing of the .hsc file. Otherwise -- the __HADDOCK__ macro doesn't end up being defined. removePreProcessedFiles :: FilePath - IO () removePreProcessedFiles dir = removeFile (dir / System/BSD/Sysctl.hs) `catch` \_ - return () Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] ANN: bsd-sysctl 1.0.3
I'm pleased to announce the release of bsd-sysctl 1.0.3, a package that provides a System.BSD.Sysctl module allowing access to the C sysctl(3) API. It should fully work on FreeBSD, NetBSD and Mac OS X platforms; it should also work on OpenBSD and Linux, although looking up sysctl's by name isn't supported there, and I believe the sysctl API doesn't return anything useful under Linux. The package is available here: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/bsd-sysctl-1.0.3 As this is my first package on hackage, I'm eager to hear about any comments on this code. Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Fast mutable arrays of ByteString?
Hello all, I have been rewriting a small utility program of mine from C to Haskell for fun. This tool reads lines from stdin or from files, shuffles them one or more times using the Fisher-Yates algorithm, and outputs the result to stdout. Since this algorithm is based on in-place updates, I've been storing my strings in a mutable array in the ST monad. Since it's holding strings I could not use an unboxed array. The resulting program works fine and seems to run at a decent speed, even though it is much slower than the original C version, slightly more so than I expected. While trying to optimize it using profiling, and playing with the number of shuffling passes, I noticed that this operation was responsible for a significant amount of the runtime, much more so than with the C version. I also noticed that the %GC time was around 56%. In order to do more tests, I wrote another version of this program which keeps the strings in a pure and immutable array, and stores the indices of this array in an unboxed mutable ST array. The shuffling is then done on this indices array instead of the strings array. This version runs much faster and only spends ~21% of its time in the garbage collector, at the cost of consuming more memory for the indices array. I'm attaching both versions of the code to this e-mail, and I'd be curious to hear about any possible improvements to it, and whether the performance of STArray of ByteString I'm observing corresponds to people's expectations. Thanks in advance, Maxime Henrion {-# LANGUAGE BangPatterns #-} module Main where import Control.Monad import Control.Monad.ST import Data.Array.ST import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as S import Data.Maybe import System.Console.GetOpt import System.Environment import System.IO import System.Random data Config = Config { separator :: Char , numPasses :: Int } deriving (Eq, Show) defaultConfig = Config { separator = '\n' , numPasses = 1 } options :: [OptDescr (Config - Config)] options = [ Option ['0'] [] (NoArg (\cfg - cfg { separator = '\0' })) expect ASCII NUL characters as separators , Option ['d'] [] (OptArg ((\d cfg - cfg { separator = d }) . maybe '\n' head) delim) use provided character as separator , Option ['n'] [] (OptArg ((\n cfg - cfg { numPasses = n }) . readNumPasses) npass) run # passes instead of just 1 ] where readNumPasses = maybe 1 (headMaybe 1 fst . reads) headMaybe _ f [x] = f x headMaybe d _ _ = d main :: IO () main = do argv - getArgs case getOpt RequireOrder options argv of (opts, args, []) - do g - newStdGen input - getInput args let Config { separator = sep , numPasses = n } = foldl (flip id) defaultConfig opts forM_ (shuffle g n (slice sep input)) $ \ln - S.putStr ln putChar sep (_, _, (err:_)) - do prog - getProgName hPutStr stderr (prog ++ : ++ err) getInput :: [FilePath] - IO ByteString getInput [] = S.getContents getInput ps = S.concat `fmap` mapM S.readFile ps slice :: Char - ByteString - (Int, [ByteString]) slice d s = slice' d s 1 [] where slice' d s !count lns = case S.elemIndex d s of Nothing- (count, s:lns) Just n | n == S.length s - 1 - (count, S.take n s:lns) -- ignore empty trailing lines | otherwise - slice' d (S.drop (n + 1) s) (count + 1) (S.take n s:lns) {-# INLINE slice #-} shuffle :: RandomGen g = g - Int - (Int, [ByteString]) - [ByteString] shuffle g n (count,lns) = runST $ do arr - newListArray (0,count - 1) lns :: ST s (STArray s Int ByteString) forM_ swaps $ \(i,j) - when (i /= j) $ do tmp - readArray arr i readArray arr j = writeArray arr i writeArray arr j tmp getElems arr where swaps = zipWith (\n k - (n - 1, k `mod` n)) (concat $ replicate n [count,count-1..2]) (randoms g) {-# LANGUAGE BangPatterns #-} module Main where import Control.Monad import Control.Monad.ST import Data.Array import Data.Array.ST import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as S import Data.Maybe import System.Console.GetOpt import System.Environment import System.IO import System.Random data Config = Config { separator :: Char , numPasses :: Int } deriving (Eq, Show) defaultConfig = Config { separator = '\n' , numPasses = 1 } options :: [OptDescr (Config - Config)] options = [ Option ['0'] [] (NoArg (\cfg - cfg { separator = '\0' })) expect ASCII NUL characters as separators , Option ['d'] [] (OptArg ((\d cfg - cfg { separator = d }) . maybe '\n' head
[Haskell-cafe] Space leak with Data.Binary and decodeFile
Hello all, I've been observing a huge space leak with some code using Data.Binary that I cannot make sense of and I hope someone here can shed some light on this, so I'll try to explain my problem as clearly as possible. I qualify the space leak as huge because if I let the program run, it will soon consume the whole memory available (~3G) and finally will get killed by the system. The code I'm writing implements a search algorithm using an inverted index. This index is built from a Trie [Int] (from the bytestring-trie package) and an Array Int ByteString. The trie maps each referenced word to an integer list that is a list of indices into the array. Here is the code for the Index datatype and the obvious Binary instance: data Index = Index { entries :: Array Int ByteString , invidx :: Trie [Int } instance Binary Index where put (Index dirs idx) = put dirs put idx get = liftM2 get get I have no problems creating and seralizing this data structure to a file. The huge leak appears instead when I'm reading this data structure from a file and try to do something with it. This is the smallest test case I came up with that can reproduce the problem : main = do idx - decodeFile list.idx; mapM_ (B.putStrLn . snd) (assocs (entries idx)) The space leak also appears when I try to touch the trie instead of the array. I've been trying tons of combinations involving adding or removing strictness annotations and seq calls in various places with no luck. I have also been adding SCC annotations and tried to profile the code. This seemed to suggest the space leak happens in the get method of the Array instance of Binary : instance (Binary i, Ix i, Binary e) = Binary (Array i e) where [...] get = do bs - get n - get -- read the length xs - replicateM n get -- now the elems. return (listArray bs xs) The output of the profiler tells me that all the space gets allocated from the replicateM n get expression. Now for the really weird part: if I load my code in GHCi and type main, I can observe the space leak. However, if I copy paste the definition of main instead, the code runs fine! This is the only circumstance I've seen this code work instead of eating all the RAM... I have been using GHC 6.10.1, binary 0.4.4 and bytestring-trie 0.1.2. If there's anything else that I can do to understand what's going on, I would gladfully hear about it. Please also tell me if I should provide more information. Thanks, -- Maxime Henrion ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Why functional programming matters
Simon Peyton-Jones wrote: Friends Over the next few months I'm giving two or three talks to groups of *non* functional programmers about why functional programming is interesting and important. If you like, it's the same general goal as John Hughes's famous paper Why functional programming matters. Audience: some are technical managers, some are professional programmers; but my base assumption is that none already know anything much about functional programming. Now, I can easily rant on about the glories of functional programming, but I'm a biased witness -- I've been doing this stuff too long. So this message is ask your help, especially if you are someone who has a somewhat-recent recollection of realising wow, this fp stuff is so cool/useful/powerful/etc. [...] I think I qualify for this: I've been a long time C coder (and still do some), doing mostly UNIX/system stuff, most notably working on the FreeBSD kernel. I only recently (1 year, maybe one and a half) started learning Haskell so I still have fresh memories about my first feelings. One of the things that particularly impressed me was parametric polymorphism. As a C programmer, you tend to rewrite code to deal with linked lists every time you need one, adding next pointers to some structure of yours. This kind of things get boring fast (one could also use the BSD sys/queue.h macros, but they're ugly). So when I discovered about parametric polymorphism, and how you can have, for instance, a length :: [a] - Int function working for any kind of lists, I was _very_ impressed. In a way, it is all perfectly logical to be able to have this kind of functions, since length doesn't need to know anything about what the list is holding, but it doesn't make it any less impressive for a C coder. Still on the parametric polymorphism topic, the Maybe datatype is what impressed me next. Everyone that has done some amount of C in his life knows how boring it is to have functions returning errors to the caller. If you're lucky, your function returns a pointer and can thus return NULL in case something went wrong. If your function returns an int and -1 has no meaning, you can use that too. But if you don't, it becomes messy quickly. It's even more annoying when the standard got it wrong, for instance the dreaded atoi() function. So, when I discovered the Maybe datatype, I was like a kid opening presents at christmas :-). The extreme simplicity of the definition of the Maybe datatype is impressive in itself, its convenience is as well, and the fact that it prevents a whole class of bugs by making it (nearly) impossible to ignore the fact that the function can fail is the cherry on top. Here are my $0.02 :-). I hope they'll be useful to you. This is mostly emotional and subjective stuff rather than technical, but I believe this is also what you're looking after. Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] freebsd-7.0BETA1 and ghc
brad clawsie wrote: On Wed, Oct 24, 2007 at 06:14:49PM -0400, Xiao-Yong Jin wrote: Is there any hope for it to be fixed before the freeze of ports tree? i believe that is the purpose of the extended beta/rc period, to allow ports maintainers a chance to get things fixed before the main release as it stands a fix was submitted by a user but has not been entered into the main ports tree (yet): http://www.freebsd.org/cgi/query-pr.cgi?pr=117235 my impression of freebsd beta releases is that the term beta is not being casually applied (like google etc), but is a true cautionary label I'll try to coordinate with fellow FreeBSD developers who are interested in Haskell, in order to ensure we'll get GHC for FreeBSD 7 soon enough. I am not sure however, that it will happen in time for 7.0-RELEASE. The ports freeze is currently planned for October 30. Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] wordsBy in the base libraries?
Hello all, What do you think about having a wordsBy function in the standard libraries? It often comes in handy. wordsBy :: (a - Bool) - [a] - [[a]] wordsBy p s = case dropWhile p s of [] - [] ':rest - (s':w) : wordsBy p s'' where (w, s'') = break p rest This version takes care of avoiding a redundant character check that is present in the standard definition of the words function, originally discovered by Neil Mitchell, see his blog post here: http://neilmitchell.blogspot.com/2007/07/equational-reasoning-in-haskell.html Then we can define the words function naturally: words :: String - [String] words = wordsBy isSpace Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] wordsBy in the base libraries?
This got a bit mangled, here's the fixed version: wordsBy :: (a - Bool) - [a] - [[a]] wordsBy p s = case dropWhile p s of [] - [] s':rest - (s':w) : wordsBy p s'' where (w, s'') = break p rest ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] wordsBy in the base libraries?
Jules Bean wrote: Maxime Henrion wrote: Hello all, What do you think about having a wordsBy function in the standard libraries? It often comes in handy. I speculate (but don't know) that the reason we don't have one is that there are quite a few choices to make: * delimiter as function (Char - Bool) or Char * delimit by single chars only or multiple (String - Bool) * multiple adjacent delimiters cause empty items, or not? * exact delimiter which occured returned as part of the result? ... my anecdotal experience is that in practice for slightly different applications you need different permutations of these choices. A single function which encompassed all the options would have a cumbersome type. I fully agree with you in that we often need slight variations of such a function, and that writing one that encompasses all different uses would probably be less convenient to use. However, we could argue just the same about the words function. Since it's there, and that it's going to stay, I still find the wordsBy function nice to have in the standard libraries. Besides, it seems to me we often need that particular behaviour of words (single character matches, eating empty items). Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] more functions to evaluate
Isaac Dupree wrote: Dan Weston wrote: applyNtimes :: (a - a) - Int - a - a This sounds like it should be in the library somewhere agree, I've used it a few times (mostly for testing things) - modulo argument order and Int vs. Integer vs. (Num a = a) What do you think about calling it iterateN instead? Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] more functions to evaluate
Dan Weston wrote: I like that name, and will henceforth use it myself until someone sees fit to add it to the Prelude! Oh, and I guess we'd also need: genericIterateN :: (a - a) - Integer - a - a Which also got me thinking, wouldn't it make more sense to have the count as the first parameter? iterateN:: Int - (a - a) - a - a genericIterateN :: Integer - (a - a) - a - a Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] more functions to evaluate
Maxime Henrion wrote: Dan Weston wrote: I like that name, and will henceforth use it myself until someone sees fit to add it to the Prelude! Oh, and I guess we'd also need: genericIterateN :: (a - a) - Integer - a - a Which also got me thinking, wouldn't it make more sense to have the count as the first parameter? iterateN:: Int - (a - a) - a - a genericIterateN :: Integer - (a - a) - a - a Woops, obviously I meant: genericIterateN :: Integral a = a - (b - b) - b - b Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Re: Haskell FFI and finalizers
Simon Marlow wrote: Maxime Henrion wrote: Stefan O'Rear wrote: On Thu, Oct 04, 2007 at 12:55:41AM +0200, Maxime Henrion wrote: When writing the binding for foo_new(), I need to open a file with fopen() to pass it the FILE *. Then I get a struct foo * that I can easily associate the the foo_destroy() finalizer. However, when finalizing the struct foo * object, I want to also close the FILE * handle. If I write a small C function for doing the finalizer myself, I still wouldn't get passed the FILE * to close, only the struct foo * pointer which is of no use. Ah, yes, this does make the situation more interesting. Looks like newForeignPtrEnv is maybe what you want? Yeah, this is what I use now. I wrote a player_finalizer() function in C, that takes a FILE * and a pointer to the struct I'm handling, and which just closes the file. I then added these sources to the mix in my .cabal file (with C-Sources, Extra-Includes, etc), and registered this new finalizer using addForeignPtrFinalizerEnv. This makes me want to ask you, what is so bad about Foreign.Concurrent that it should be avoided at almost any cost? It sure is likely to be much slower than just calling a plain C finalizer, but aren't Haskell threads super-cheap anyways? In GHC ordinary ForeignPtr finalizers are implemented using Foreign.Concurrent anyway. It's not so much that Foreign.Concurrent should be avoided at all costs, but rather finalizers in general should be avoided, especially if you really care about when they run (i.e. bad things could happen if they run late or at unpredictable times). The Haskell code is not run by the garbage collector, rather the garbage collector figures out which finalizers need running and creates a thread to run them. It's perfectly safe to have C finalizers that invoke Haskell code using GHC, although this is explicitly undefined by the FFI spec. The reason that Foreign.Concurrent is separate from Foreign.ForeignPtr is that it does essentially require concurrency to implement, whereas ordinary C finalizers can be run by the GC (although GHC doesn't do it this way). Thank you for those precisions, Simon. It seems that even if using the Foreign.Concurrent module isn't a problem per-self, I'd be better off using a plain C finalizer that I write myself, if only for portability with other FFI implementations. Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Haskell FFI and finalizers
Stefan O'Rear wrote: On Thu, Oct 04, 2007 at 12:55:41AM +0200, Maxime Henrion wrote: When writing the binding for foo_new(), I need to open a file with fopen() to pass it the FILE *. Then I get a struct foo * that I can easily associate the the foo_destroy() finalizer. However, when finalizing the struct foo * object, I want to also close the FILE * handle. If I write a small C function for doing the finalizer myself, I still wouldn't get passed the FILE * to close, only the struct foo * pointer which is of no use. Ah, yes, this does make the situation more interesting. Looks like newForeignPtrEnv is maybe what you want? Yeah, this is what I use now. I wrote a player_finalizer() function in C, that takes a FILE * and a pointer to the struct I'm handling, and which just closes the file. I then added these sources to the mix in my .cabal file (with C-Sources, Extra-Includes, etc), and registered this new finalizer using addForeignPtrFinalizerEnv. This makes me want to ask you, what is so bad about Foreign.Concurrent that it should be avoided at almost any cost? It sure is likely to be much slower than just calling a plain C finalizer, but aren't Haskell threads super-cheap anyways? I'm not doubting your advices at all, but want to make sure I understand all this fully :-). Thanks again, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Haskell FFI and finalizers
Hello all, I have recently developed a small set of bindings for a C library, and encountered a problem that I think could be interesting to others. My problem was that the C function I was writing bindings to expects to be passed a FILE *. So, I had basically two possibles routes to take: 1) Mimic the C API and have the haskell function take a Handle. Unfortunately, I can see no way to go from a Handle to a Ptr CFile, at least no portable way, so I discarded this option. 2) Deviate from the C API slightly and have the haskell function take a FilePath instead of a Handle. This is the option I chose, and this is where things get interesting. In order to pass a Ptr CFile (FILE *) to the C function, I had to call fopen() myself, using a usual FFI binding: foreign import ccall unsafe fopen fopen :: CString - CString - IO (Ptr CFile) That's the easy part. Now my problem was that I had to find a way to automatically close this FILE * when it isn't used anymore, in order not to leak FILE structures (and thus fds, etc). A finalizer is typically what I need, but unfortunately, a finalizer has a very strict shape: type FinalizerPtr a = FunPtr (Ptr a - IO ()) That is, a finalizer can only be a pointer to a foreign function, and the foreign function itself needs a quite specific shape. And then I discovered Foreign.Concurrent, which allows one to associate a plain Haskell IO action to a pointer. The 'Foreign.Concurrent' name is a bit misleading to me; it seems this module is named so because it needs concurrency itself, rather than providing stuff for concurrency. So, in the end, I've got this code: import Foreign import Foreign.C import qualified Foreign.Concurrent as FC ... data PlayerStruct type Player = ForeignPtr PlayerStruct ... foreign import ccall unsafe dd_newPlayer_file dd_newPlayer_file :: Ptr CFile - Ptr ImageStruct - IO (Ptr PlayerStruct) foreign import ccall unsafe dd_destroyPlayer destroyPlayerFinal :: FunPtr (Ptr PlayerStruct - IO ()) foreign import ccall unsafe fopen fopen :: CString - CString - IO (Ptr CFile) foreign import ccall unsafe fclose fclose :: Ptr CFile - IO CInt ... mkFinalizedPlayer :: Ptr PlayerStruct - IO Player mkFinalizedPlayer = newForeignPtr destroyPlayerFinal newPlayerFile :: FilePath - Image - IO Player newPlayerFile path image = do withCString path $ \cpath - do withCString rb $ \cmode - do file - throwErrnoIfNull fopen: (fopen cpath cmode) withForeignPtr image $ \ptr - do player - dd_newPlayer_file file ptr = mkFinalizedPlayer FC.addForeignPtrFinalizer player (fclose file return ()) return player So I'm adding the usual finalizer, and with the help of Foreign.Concurrent, I can add a second free-form one (fclose file return ()), in order to close the file I opened at an appropriate time. I'm looking forward hearing about other people's opinions, and wether this is a correct solution to the initial problem or not. I think there is another way to solve this, which is to provide the finalizer still in haskell code, but export the haskell code using FFI, so that I can use it as a plain, normal finalizer. I'm still unsure about this. Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Haskell FFI and finalizers
Stefan O'Rear wrote: On Wed, Oct 03, 2007 at 05:57:58PM +0200, Maxime Henrion wrote: I have recently developed a small set of bindings for a C library, and encountered a problem that I think could be interesting to others. My problem was that the C function I was writing bindings to expects to be passed a FILE *. So, I had basically two possibles routes to take: That's the easy part. Now my problem was that I had to find a way to automatically close this FILE * when it isn't used anymore, in order not to leak FILE structures (and thus fds, etc). A finalizer is typically what I need, but unfortunately, a finalizer has a very strict shape: type FinalizerPtr a = FunPtr (Ptr a - IO ()) That is, a finalizer can only be a pointer to a foreign function, and the foreign function itself needs a quite specific shape. And then I discovered Foreign.Concurrent, which allows one to associate a plain Haskell IO action to a pointer. The 'Foreign.Concurrent' name is a bit misleading to me; it seems this module is named so because it needs concurrency itself, rather than providing stuff for concurrency. NOOO! Foreign.Concurrent, as its name implies, works by forking threads, and it should be avoided at almost any cost. The correct solution is: void close_file_finalizer(FILE *file) { if (fclose(file) 0) { /* do something sensible here */ } } That wouldn't work; my problem is that this finalizer for closing the FILE * needs to be called when another pointer gets garbage collected. This is because I'm opening the file in order to pass to some function which creates an objet and returns it to me. To parody the situation: struct foo *foo_new(FILE *); void foo_destroy(struct foo *); When writing the binding for foo_new(), I need to open a file with fopen() to pass it the FILE *. Then I get a struct foo * that I can easily associate the the foo_destroy() finalizer. However, when finalizing the struct foo * object, I want to also close the FILE * handle. If I write a small C function for doing the finalizer myself, I still wouldn't get passed the FILE * to close, only the struct foo * pointer which is of no use. Thanks, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] standard function
Steffen Mazanek wrote: Hello, is there a function f::[a-b]-a-[b] in the libraries? Couldn't find one using hoogle although this seems to be quite a common thing... As far as I know, there is no standard function doing that, though it is easily implemented: mapApply xs x = map ($ x) xs or just: mapApply x = map ($ x) If you don't mind the parameters being reversed. The 'mapApply' name is probably terrible, I'm sure other people would have better suggestions for the naming :-). Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] GHC 6.7 and Associated Types
Hello guys, I've been documenting myself on associated types, which look like a very nice way to deal with the problems that arise with multi-parameter type classes. As an exercise, I am trying to rewrite the MonadState type class from the mtl package without functional dependencies. Here is my (probably very naive) approach : class MonadState m where type StateType m :: * get :: m StateType put :: m StateType - m () As for instances: instance MonadState (State s) where type StateType = s -- this is line 22 get= State $ \s - (s, s) put s = State $ \_ - ((), s) I think I'm probably doing some very stupid thing and missing important points. In any case, here's the error I get : State.hs:22:19: Not in scope: type variable `s' Failed, modules loaded: none. I'd be happy to be explained why this doesn't make sense, and how I should proceed to implement this correctly. I have tried various other approaches with no luck yet. Thanks, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: GHC 6.7 and Associated Types
apfelmus wrote: Maxime Henrion wrote: class MonadState m where type StateType m :: * get :: m StateType put :: m StateType - m () As for instances: instance MonadState (State s) where type StateType = s -- this is line 22 When defining the type function StateType, you have to give it the required argument m = State s: type StateType (State s) = s get= State $ \s - (s, s) put s = State $ \_ - ((), s) I tried that too already, it gives: State.hs:19:39: Kind mis-match Expected kind `k - *', but `()' has kind `*' In the type `m ()' In the type `m StateType - m ()' In the class declaration for `MonadState' Line 19 being the definition of put in the class. Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: GHC 6.7 and Associated Types
Simon Peyton-Jones wrote: Associated *data* types should work in the HEAD (=6.7). But associated *type synonyms* do not, I'm afraid. We are actively working on it, but it'll be a couple of months at least I guess. You can see the state of play, and description of where we are up to here http://hackage.haskell.org/trac/ghc/wiki/TypeFunctions Ah, it's good to know that it wasn't just me being stupid :-). Thank you, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: GHC 6.7 and Associated Types
apfelmus wrote: Maxime Henrion wrote: apfelmus wrote: Maxime Henrion wrote: class MonadState m where type StateType m :: * get :: m StateType put :: m StateType - m () As for instances: instance MonadState (State s) where type StateType = s -- this is line 22 When defining the type function StateType, you have to give it the required argument m = State s: type StateType (State s) = s get= State $ \s - (s, s) put s = State $ \_ - ((), s) I tried that too already, it gives: State.hs:19:39: Kind mis-match Expected kind `k - *', but `()' has kind `*' In the type `m ()' In the type `m StateType - m ()' In the class declaration for `MonadState' Ah, oh, I didn't even check whether the types in the class are good. I'm not sure, but don't you want class MonadState m where type StateType m :: * get :: m (StateType m) put :: StateType m - m () ? Then, the substitutions m = State s and StateType (State s) = s yields the expected types for put and get: get :: (State s) s put :: s - (State s) () Ah, I tried something like that too, and then I get errors in the definition of the instance : State.hs:23:19: Couldn't match expected type `StateType (State s)' against inferred type `s' (a rigid variable) `s' is bound by the instance declaration at State.hs:21:27 Expected type: State s (StateType (State s)) Inferred type: State s s In the expression: State $ (\ s - (s, s)) In the definition of `get': get = State $ (\ s - (s, s)) State.hs:24:19: Couldn't match expected type `s' (a rigid variable) against inferred type `StateType (State s)' `s' is bound by the instance declaration at State.hs:21:27 Expected type: State s () Inferred type: State (StateType (State s)) () In the expression: State $ (\ _ - ((), s)) In the definition of `put': put s = State $ (\ _ - ((), s)) I would expect GHC to see that 'State s (StateType (State s))' is the same as 'State s s', per the definition of StateType. I'm not sure how to express get differently so that it matches, and similarly for put. If I write: get= State $ \s - (StateType (State s), s) I get: State.hs:23:34: Not in scope: data constructor `StateType' Thanks, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] A convenient way to deal with conditional function composition?
Chris Kuklewicz wrote: Nicolas Frisby wrote: Not portably. [EMAIL PROTECTED]:~$ ghc-6.4.2 -e '( (foo++) `Data.Monoid.mappend` (bar++) ) END' foobarEND [EMAIL PROTECTED]:~$ ghc-6.6 -e '( (foo++) `Data.Monoid.mappend` (bar++) ) END' fooENDbarEND -- 6.6 sources instance Monoid b = Monoid (a - b) where mempty _ = mempty mappend f g x = f x `mappend` g x Stefan Thanks for the reminder. So the fixed 6.6 code is import Control.Monad(when) import Control.Monad.Writer(Writer,tell,execWriter) import Data.Monoid(Endo(..)) type Writes = Writer (Endo String) () data PieceType = Pawn | Other deriving (Eq,Show) type File = Int type Square = Int data Move = Move { movePiece :: PieceType, moveFile :: Maybe File, moveTarget:: Square, moveIsCapture :: Bool --movePromotion :: Maybe PieceType } deriving (Eq) instance Show Move where showsPrec = showsPrec_Move tShow :: Show a = a - Writes tShow = tell . Endo . shows tChar :: Char - Writes tChar = tell . Endo . (:) tString :: String - Writes tString = tell . Endo . (++) showsPrec_Move :: Int - Move - ShowS showsPrec_Move _ Move { movePiece = p , moveFile = f , moveTarget= s , moveIsCapture = c } = appEndo . execWriter $ do when (p/=Pawn) (tShow p) maybe (return ()) tShow f when c (tChar 'x') tShow s testMove = Move Other (Just 6) 10 True Thanks a lot for all the nice answers, guys. I have a few remaining questions if you don't mind though. Should I expect significant performance reduction by using the Writer monad here, as opposed to the version I wrote? And, most importantly, I'd like to know how *you* would write this if you had to :-). Would you juse the Writer monad version? Thanks, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] A convenient way to deal with conditional function composition?
Hello all, I have found myself writing instances of Show for some types of mine, and I did so by defining the showsPrec function, for performance reasons. I ended up with code that I find quite inelegant. Here's an example: data Move = Move { movePiece :: PieceType, moveFile :: Maybe File, moveTarget:: Square, moveIsCapture :: Bool --movePromotion :: Maybe PieceType } deriving (Eq) instance Show Move where showsPrec _ Move { movePiece = p, moveFile = f, moveTarget= s, moveIsCapture = c } = (if p /= Pawn then shows p else id) . (maybe id shows f) . (if c then ('x':) else id) . shows s I considered writing a conditional composiion combinator to avoid all the 'if foo then f else id' code. Something looking like this: f .? True g = f . g f .? False g = f I'm not sure this is the best approach though, and I would be happy to hear about your suggestions for improving the style of this code, or any other comment that you think is appropriate. Thanks, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Haskell Chess
Steffen Mazanek wrote: Hello again, first of all, thank you Don for your help in making hsChess accessible. I have to have a look at darcs and cabal first :-) I have added some more content and a discussion page to the wiki, please contribute your thoughts. Furthermore I added a link to the german project and task description used in the exercises; the English version will be the wiki (although it has no convert2tex function). Best regards, Steffen I stepped onto your mail and found it particularly interesting since I'm currently writing a chess client in Haskell, using GTK+, glade and the nice Cairo library :-). It is called LambdaChess! The code is completely embryonic and totally useless at the moment, but there's a base for a decent GUI interface, with an SVG board, so easily themable. There is also some base code for a PGN file parser written using Parsec, and the whole thing is cabalized. The pieces aren't even drawn yet, but that should be quite easy to do, and I've found a few nice SVG piece sets. The PGN parser doesn't completely parses SAN moves yet, nor does it parse NAG annotations. It doesn't properly validates the presence of the mandatory tags, and so on... I guess I should stop since it's going to be huge if I'm listing all the missing features :-). Ultimately, it'd be nice if this code was able to handle local games between two humans and also playing against the various chess engines (crafty, gnuchess, sjeng, etc...). If it was also able to connect to FICS, it would be the absolute greatness :D. If you or anyone else on this mailing list feels like joining the fun, please do! The code is available here: http://mu.org/~mux/LambdaChess/ Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Haskell Chess
Andrew Wagner wrote: Steffen, I've done some chess AI programming in the past, so I'd be happy to help with this project. I have some pretty fundamental design suggestions that I'll write up for the wiki page. Maxime, Handling different chess engines isn't hard. chess engine communication is pretty standardized - you would just need to add support for the winboard and/or UCI protocols. FICS is a little bit harder, but it's just a pure test stream over a socket, somewhat like IRC, but less defined. ICC (another chess server) has a slightly better-defined protocol. I can get you more details on any of these protocols (except maybe FICS, which I don't think is documented), if you'd like. By the way, how portable is your graphics code going to be? I haven't yet looked in details at the winboard protocol or UCI, but having used crafty and gnuchess in CLI, I have a pretty good idea how this is all working, and this is indeed what I intend to do. As for FICS, I have often played on it through telnet, so I have a good knowledge of this text-based protocol. I don't know of any standard for FICS, but it isn't strictly required to get something working. I'd be interested in ICC support too, but since it's not free, it'll have to wait :-). As for the portability of the my graphics code, I can just say it's GTK+, using Glade XML files, Cairo and SVG on top of Cairo. All of this is supposed to work fine on Windows, if that's what you were asking. I'm not sure about OS X but I think it could also work there. My primary target is UNIX. For those of you who know it, I think BabasChess under Windows sums up what I'd like to obtain in the end quite nicely, features-wise. I'm looking forward receiving your patches! ;-) Cheers, Maxime Sounds like this will be an interesting project. I look forward to it! Andrew On 3/19/07, Duncan Coutts [EMAIL PROTECTED] wrote: On Mon, 2007-03-19 at 12:14 +0100, Maxime Henrion wrote: I stepped onto your mail and found it particularly interesting since I'm currently writing a chess client in Haskell, using GTK+, glade and the nice Cairo library :-). It is called LambdaChess! Cool! When you have something you want to show off, we could always do with more expositions screen shots etc for the Gtk2Hs website like the things we've got here: http://haskell.org/gtk2hs/archives/category/screenshots/ And I'm glad someone is using the new SVG module that got added in the latest Gtk2Hs release :-) Duncan ___ 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
[Haskell-cafe] A valuable new combinator for Parsec?
Hello all, While using the very nice option combinator of Parsec recently, it seemed to me that it would be useful to have a more specific kind of combinator for optional tokens that wraps the token into a Maybe type. So, that gives: pmaybe :: GenParser tok st a - GenParser tok st (Maybe a) pmaybe p = option Nothing (p = return . Just) I've been using it happily with some code of mine. Do people think that it would be generally useful to have in Parsec? Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] how to calculate the sum of list of lists?
Miranda Kajtazi wrote: Help, How to calculate the sum of list of lists in Haskell? Do you mean something of the form Num a = [[a]] - a ? If so, this should do it: Prelude let foo = sum . concat Prelude foo [[1,2,3],[4,5]] 15 Cheers, Maxime ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe