Re: [Haskell-cafe] Compiler's bane
Jonathan Cast wrote: On Fri, 2008-08-29 at 20:56 +0100, Andrew Coppin wrote: I've been playing with this today, and no matter what rules I come up with, it seems to be ridiculously easy to put the interpretter into an infinite loop from which it will never escape. Is there any way to know which binds are worth expanding and which ones aren't? (I have a sinking feeling this might be equivilent to the Halting Problem...) For example, if you have let x = f y; y = g x in x then since all the functions are free variables, there's really nothing much useful you can do to simplify this any further. However, my interpretter merrily goes into an endless loop building a huge expression like f (g (f (g (f (g... Is it possible to avoid this? If you want to avoid infinite normal forms (or just plain lack of normal forms, as in let x = x in x or (\x - x x) (\ x - x x)), you need to follow three rules: 1) Static typing 2) No value recursion 3) If you allow data types, no recursive data types Otherwise, your language will be Turing-complete, so yes, trying to determine ahead of time if even a HNF exists will be the halting problem. If you really want to write a general-purpose evaluator, then infinite normal forms may not be an issue, as long as they are generated lazily, so your evaluator can at least print something out while it goes into an infinite loop. Otherwise, you can declare f x, where f is an unknown function, a HNF, and stop at that point, or go on only under the client's control. The optimizers used by GHC and YHC pick one function out of each recursive binding group, and just refuse to inline it at all. If you don't mind producing expressions that aren't really in any definable HNF, that would be an alternative as well. Right. So if I have, say, the factorial function defined using the Y combinator, there's no way to stop the interpretter expanding an infinite number of copies of Y, even though in theory the factorial function should terminate? Oh well, I guess I'll just have to live with that one. Maybe I can make the binding to expand user-selectable or something... ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Compiler's bane
On Sun, Aug 31, 2008 at 12:46 AM, Andrew Coppin [EMAIL PROTECTED] wrote: Right. So if I have, say, the factorial function defined using the Y combinator, there's no way to stop the interpretter expanding an infinite number of copies of Y, even though in theory the factorial function should terminate? Well, this is exactly what ghci is doing; you just have to choose an evaluation order that makes sense. Lets consider a simple translation for recursive lets: let x = exp1 in exp2 (where x may be free in exp1 and/or exp2) Here's a simple translation into lambda-calculus: (\x. exp2) (y (\x. exp1)) (Of course, this representation for let can lose sharing; without knowing what you have or your goals I don't know if you care). Now, you just have to choose a y-combinator that makes sense for your evaluation order. If you do normal-order evaluation like Haskell (non-strict), this Y should work for you: y = \f. (\x. f (x x)) (\x. f (x x)) Oh well, I guess I'll just have to live with that one. Maybe I can make the binding to expand user-selectable or something... Now, if you are eagerly-expanding the entire expression, trying to get to head normal form, then any expression that ends up with y in it won't terminate. But if you use normal form evaluation order, then if a normal form exists, you will find it and terminate. So evaluating fact to normal form won't terminate, but evaluating fact 5 should. -- ryan ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Calling Lockheed, Indra, Thales, Raytheon
You could dump the archives, grep out the names and then Google... -- _jsn ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
Dan Doel wrote: Here's a first pass: -- snip -- {-# LANGUAGE Rank2Types, GeneralizedNewtypeDeriving #-} module Unique where import Control.Monad.Reader import Control.Monad.Trans import Control.Concurrent.MVar -- Give Uniques a phantom region parameter, so that you can't accidentally -- compare Uniques from two different uniqueness sources. newtype Unique r = Unique Integer deriving Eq newtype U r a = U { unU :: ReaderT (MVar Integer) IO a } deriving (Functor, Monad, MonadIO) -- Higher rank type for region consistency runU :: (forall r. U r a) - IO a runU m = newMVar 0 = runReaderT (unU m) newUnique :: U r (Unique r) newUnique = U (do source - ask val - lift $ takeMVar source let next = val + 1 lift $ putMVar source next return $ Unique next) -- hashUnique omitted -- snip -- It's possible that multiple unique sources can exist in a program with this implementation, but because of the region parameter, the fact that a Unique may not be globally unique shouldn't be a problem. If your whole program needs arbitrary access to unique values, then I suppose something like: main = runU realMain realMain :: U r () realMain = ... is in order. Insert standard complaints about this implementation requiring liftIO all over the place if you actually want to do other I/O stuff inside the U monad. Well that wouldn't be my main complaint :-) Thanks for taking the time to do this Dan. I think the safety requirement has been met, but I think it fails on the improved API. The main complaint would be what I see as loss of modularity, in that somehow what should be a small irrelevant detail of the implementation of some obscure module somewhere has propogated it's way all the way upto main. This is something it seems to have in common with all other attempts I've seen to solve the global variable problem without actually using a..you know what :-) It doesn't matter whether it's explicit state handle args, withWhateverDo wrappers, novel monads or what. They all have this effect. To me this seems completely at odds with what I thought was generally accepted wisdom of how to write good maintainable, modular software. Namely hiding as much implemention detail possible and keeping APIs as simple and stable as they can be. I don't know if I'm alone in that view nowadays. I'm also not sure I understand why so many people seem to feel that stateful effects must be accounted for somehow in the args and/or types of the effecting function. Like if I had.. getThing :: IO Thing ..as an FFI binding, nobody would give it a moments thought. They'd see it from it's type that it had some mysterious world state dependent/effecting behaviour, but would be quite happy to just accept that the didn't really need to worry about all that magic... instead they'd accept that it just works. Why then, if I want to implement precisely the same thing in Haskell (using a global variable) does it suddenly become so important for this stateful magic to be accounted for? Like the presence of that global variable must be made so very painfully apparent in main (and everywhere else on the dependency path too I guess). In short, I just don't get it :-) Purists aren't going to like it, but I think folk *will* be using real global variables in I/O libs for the forseeable future. Seems a shame that they'll have to do this with unsafePerformIO hack though :-( Regards -- Adrian Hey ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Re: [Haskell] Top Level -
On Sat, 30 Aug 2008, Ashley Yakeley wrote: OK. Let's call it top-level scope. Haskell naturally defines such a thing, regardless of processes and processors. Each top-level - would run at most once in top-level scope. If you had two Haskell runtimes call by C code, each would have its own memory allocator and GC; IORefs, Uniques and thunks cannot be shared between them; and each would have its own top-level scope, even though they're in the same process. That sounds more feasible - though it does constrain a plugin architecture (in which Haskell code can dynamically load other Haskell code) to cooperate with the loading RTS and not load multiple copies of modules; this might make linking tricky. There's also the problem Duncan Coutts mentioned about loading multiple versions of the same module - what are the semantics of - in relation to that? Also, it's no use for mediating access to a resource or library that can only be accessed once, right? In fact, even without the problem of two Haskell runtimes in one process this can't work, since some library in another language might also choose to access that resource or library. What applications does this leave beyond Data.Unique and Random? Ganesh ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On Sat, 30 Aug 2008, Adrian Hey wrote: Ganesh Sittampalam wrote: Well, yes, but if I implemented a library in standard Haskell it would always be safely serialisable/deserialisable (I think). So the global variables hack somehow destroys that property - how do I work out why it does in some cases but not others? This has nothing to do with the use of global variables. If you have a set of values that are guaranteed to be distinct (unique) and you add another random/arbitrary value to that set you have no way of knowing that it is different from any current member (other than searching the entire set, assuming it's available). OK, never mind about this. I was thinking that referential transparency was violated by remoting, but since unique values can only be constructed in IO, I think I was wrong. Well, I've never seen a convincing use case for global variables :-) Well apart from all the libs that couldn't be implemented with them... They can't be implemented with an interface that is completely oblivious to the fact that the libraries require some state. Dynamic loading and plugins work fine with standard Haskell now, because nothing in standard Haskell breaks them. The - proposal might well break them, which is a significant downside for it. I don't see how, but if so - bindings are not the cause of the brokeness. They'd still be broken using the unsafePerformIO hack. Which places the unsafePerformIO hack at fault, seeing as it's unsafe and a hack and all :-) If - was standard then it'd be up to everyone else to work round its limitations. In general, the smaller the world that the Haskell standard lives in, the less it can interfere with other concerns. - massively increases that world, by introducing the concept of a process scope. All IORefs,MVars,Chans scope across the entire process defined by main. Or at least they *should*, if they don't then something is already badly wrong somewhere. This has nothing to do with whether or not they appear at top level. This is what an IORef/MVar whatever is defined to be. Their scope is where they can be used, and this is something we can explicitly track by inspecting the program text. If they are just used in one part of the program, their scope is limited to that part of the program. But then again, I'm sure that some that will be adamant that any way of making global variables is a hack. But they'll still be happy to go on using file IO, sockets etc regardless, blissfully unaware of the hacks they are dependent on :-) I'm not sure of precisely what you mean here, but stdin, stdout and stderr are things provided by the OS to a process. That's what defines them as having process scope, not something the Haskell language or RTS does. Those rules aren't actually strong enough to provide a guarantee of process level scope. The rules for - bindings shouldn't have to guarantee this. This should be guaranteed by newMVar returning a new *MVar*, wherever it's used (for example). The issue is whether the - is run multiple times in a single process or not, rather than how the thing it calls behaves. I mean semantic faults, as in the proposal just doesn't do what it promises for some subtle reason. It doesn't provide once-only semantics across an entire process in cases involving dynamic loading or two Haskell libraries together with RTS separately linked into the same C program. I don't know whether you intend that it does promise that or not, but it seems to be necessary for many of the applications that are used to justify it. If you consider not giving you thread local variables a fault I guess you're entitled to that view, but this was never the intent of the proposal in the first place (that's not what people are trying to do when they use the unsafePerformIO hack). The thread-local variables point was a relatively minor issue for me compared to the dynamic loading and related issues. Cheers, Ganesh ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On 2008 Aug 31, at 10:20, Ganesh Sittampalam wrote: On Sat, 30 Aug 2008, Adrian Hey wrote: But then again, I'm sure that some that will be adamant that any way of making global variables is a hack. But they'll still be happy to go on using file IO, sockets etc regardless, blissfully unaware of the hacks they are dependent on :-) I'm not sure of precisely what you mean here, but stdin, stdout and stderr are things provided by the OS to a process. That's what defines them as having process scope, not something the Haskell language or RTS does. But their representations in Haskell must have the same scope and are therefore de facto global variables. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED] system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED] electrical and computer engineering, carnegie mellon universityKF8NH ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 10:20, Ganesh Sittampalam wrote: I'm not sure of precisely what you mean here, but stdin, stdout and stderr are things provided by the OS to a process. That's what defines them as having process scope, not something the Haskell language or RTS does. But their representations in Haskell must have the same scope and are therefore de facto global variables. Yep, but this is not Haskell providing a way to make global variables, it is just providing an interface to ones that already exist. The point is that the RTS can't provide (process-scope) global variables of its own invention, because it can't guarantee to be running at the top-level of a process, which it needs to be in order to control their construction. Cheers, Ganesh ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On 2008 Aug 31, at 10:29, Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 10:20, Ganesh Sittampalam wrote: I'm not sure of precisely what you mean here, but stdin, stdout and stderr are things provided by the OS to a process. That's what defines them as having process scope, not something the Haskell language or RTS does. But their representations in Haskell must have the same scope and are therefore de facto global variables. Yep, but this is not Haskell providing a way to make global variables, it is just providing an interface to ones that already exist. The point is that the RTS can't provide (process-scope) But that is done the same way as providing general global variables, so you can't get away from it. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED] system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED] electrical and computer engineering, carnegie mellon universityKF8NH ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 10:29, Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 10:20, Ganesh Sittampalam wrote: I'm not sure of precisely what you mean here, but stdin, stdout and stderr are things provided by the OS to a process. That's what defines them as having process scope, not something the Haskell language or RTS does. But their representations in Haskell must have the same scope and are therefore de facto global variables. Yep, but this is not Haskell providing a way to make global variables, it is just providing an interface to ones that already exist. The point is that the RTS can't provide (process-scope) But that is done the same way as providing general global variables, so you can't get away from it. I don't follow what you mean. stdin, stdout and stderr are just file descriptors 0, 1 and 2, aren't they? You can create them as many times as you want with using that information without causing any confusion or conflict. Whereas the - proposal has a once-only requirement. Ganesh ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On 2008 Aug 31, at 10:34, Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 10:29, Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 10:20, Ganesh Sittampalam wrote: I'm not sure of precisely what you mean here, but stdin, stdout and stderr are things provided by the OS to a process. That's what defines them as having process scope, not something the Haskell language or RTS does. But their representations in Haskell must have the same scope and are therefore de facto global variables. Yep, but this is not Haskell providing a way to make global variables, it is just providing an interface to ones that already exist. The point is that the RTS can't provide (process-scope) But that is done the same way as providing general global variables, so you can't get away from it. I don't follow what you mean. stdin, stdout and stderr are just file descriptors 0, 1 and 2, aren't they? You can create them as many times as you want with using that information without causing any confusion or conflict. Whereas the - proposal has a once-only requirement. The convention is to provide buffered versions to improve the performance of file I/O. These buffered filehandles must be created once per runtime instance (and ideally once per process so multiple runtimes don't find themselves overwriting each others' output). -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED] system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED] electrical and computer engineering, carnegie mellon universityKF8NH ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On Sun, 31 Aug 2008, Adrian Hey wrote: Thanks for taking the time to do this Dan. I think the safety requirement has been met, but I think it fails on the improved API. The main complaint would be what I see as loss of modularity, in that somehow what should be a small irrelevant detail of the implementation of some obscure module somewhere has propogated it's way all the way upto main. That's the key point, as I see it - they aren't irrelevant details of the implementation, they are requirements the implementation places on its context in order for that implementation to be correct. So they should be communicated appropriately. To me this seems completely at odds with what I thought was generally accepted wisdom of how to write good maintainable, modular software. Namely hiding as much implemention detail possible and keeping APIs as simple and stable as they can be. I don't know if I'm alone in that view nowadays. It's no problem to hide implementation detail, but I don't think you should hide the *requirement* of the implementation that it has constraints on how it is called, namely that it requires once-only initialisation or whatever. Purists aren't going to like it, but I think folk *will* be using real global variables in I/O libs for the forseeable future. Seems a shame that they'll have to do this with unsafePerformIO hack though :-( From a purist point of view, it's a shame that they choose to do it at all :-) Ganesh ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 10:34, Ganesh Sittampalam wrote: I don't follow what you mean. stdin, stdout and stderr are just file descriptors 0, 1 and 2, aren't they? You can create them as many times as you want with using that information without causing any confusion or conflict. Whereas the - proposal has a once-only requirement. The convention is to provide buffered versions to improve the performance of file I/O. These buffered filehandles must be created once per runtime instance (and ideally once per process so multiple runtimes don't find themselves overwriting each others' output). In that case it seems that any library that might be used from a runtime that isn't the top-level of a process should avoid doing IO to those handles, for fear of producing output corruption? Ganesh ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On 2008 Aug 31, at 10:44, Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 10:34, Ganesh Sittampalam wrote: I don't follow what you mean. stdin, stdout and stderr are just file descriptors 0, 1 and 2, aren't they? You can create them as many times as you want with using that information without causing any confusion or conflict. Whereas the - proposal has a once- only requirement. The convention is to provide buffered versions to improve the performance of file I/O. These buffered filehandles must be created once per runtime instance (and ideally once per process so multiple runtimes don't find themselves overwriting each others' output). In that case it seems that any library that might be used from a runtime that isn't the top-level of a process should avoid doing IO to those handles, for fear of producing output corruption? You handle it the same way you handle I/O with concurrency: either one of the runtimes is privileged to the extent that it owns the filehandles and other runtimes must make an inter-runtime call to use them, or the filehandle structures include locking and are shared across runtimes. Both of these are used in Haskell (see most GUI libraries for the former, and the implementation of Handles for the latter). -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED] system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED] electrical and computer engineering, carnegie mellon universityKF8NH ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Adrian Hey wrote: Thanks for taking the time to do this Dan. I think the safety requirement has been met, but I think it fails on the improved API. The main complaint would be what I see as loss of modularity, in that somehow what should be a small irrelevant detail of the implementation of some obscure module somewhere has propogated it's way all the way upto main. That's the key point, as I see it - they aren't irrelevant details of the implementation, they are requirements the implementation places on its context in order for that implementation to be correct. So they should be communicated appropriately. Eh? Please illustrate your point with Data.Unique. What requirements does it place on it's context? (whatever that might mean :-) It just does what it says on the tin AFAICS. There are no requirements it places on clients (to use an OO term), as should any halfway decent API IMO. To me this seems completely at odds with what I thought was generally accepted wisdom of how to write good maintainable, modular software. Namely hiding as much implemention detail possible and keeping APIs as simple and stable as they can be. I don't know if I'm alone in that view nowadays. It's no problem to hide implementation detail, but I don't think you should hide the *requirement* of the implementation that it has constraints on how it is called, namely that it requires once-only initialisation or whatever. No decent API should require this. Data.Unique certainly doesn't. In fact is debatable whether any API should requre an initalisation call at all before other stuff should be called (the other stuff check initialisation has occured and do it itself if necessary). The real irony of your remark is that making APIs this robust is practically impossible *without* using global variables, and you're now saying that because they've done this work to eliminate these constraints they now have to be held to account for this with an absurd API. Seems like a clear case of no good deed going unpunished :-) Regards -- Adrian Hey ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On 2008 Aug 31, at 11:20, Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 10:44, Ganesh Sittampalam wrote: In that case it seems that any library that might be used from a runtime that isn't the top-level of a process should avoid doing IO to those handles, for fear of producing output corruption? You handle it the same way you handle I/O with concurrency: either one of the runtimes is privileged to the extent that it owns the filehandles and other runtimes must make an inter-runtime call to use them, or the filehandle structures include locking and are shared across runtimes. Both of these are used in Haskell (see most GUI libraries for the former, and the implementation of Handles for the latter). Where do the filehandle structures live in the latter case? The place you clearly think so little of that you need to ask: process-global (or process-local depending on how you think about it) storage. And everything in that storage must have locking. (And this requirement makes it similar in some ways to other non-directly- accessible process state such as (say) the process id.) -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED] system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED] electrical and computer engineering, carnegie mellon universityKF8NH ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 11:20, Ganesh Sittampalam wrote: Where do the filehandle structures live in the latter case? The place you clearly think so little of that you need to ask: process-global (or process-local depending on how you think about it) storage. And everything in that storage must have locking. I'm sorry if this makes me seem ignorant, but I'd never heard of such a thing before. What is the API for accessing such storage, and/or where can I find its documentation? Cheers, Ganesh ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On Sun, 31 Aug 2008, Adrian Hey wrote: Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Adrian Hey wrote: Thanks for taking the time to do this Dan. I think the safety requirement has been met, but I think it fails on the improved API. The main complaint would be what I see as loss of modularity, in that somehow what should be a small irrelevant detail of the implementation of some obscure module somewhere has propogated it's way all the way upto main. That's the key point, as I see it - they aren't irrelevant details of the implementation, they are requirements the implementation places on its context in order for that implementation to be correct. So they should be communicated appropriately. Eh? Please illustrate your point with Data.Unique. What requirements does it place on it's context? (whatever that might mean :-) It requires that its context initialises it precisely once. Data.Unique is actually a poor example, as it is actually fine to initialise it multiple times as long as the resulting Unique values aren't treated as coming from the same datatype. But equally it can be implemented with IORefs, so it's not a good advert for the need for global variables. The real irony of your remark is that making APIs this robust is practically impossible *without* using global variables, and you're now saying that because they've done this work to eliminate these constraints they now have to be held to account for this with an absurd API. I think there are two cases to consider here. A Data.Unique style library, which requires genuinely *internal* state, and which is agnostic to having multiple copies of itself loaded simultaneously. In that case, there is no requirement for a process-level scope for -, just that each instance of the library is only initialised once - the RTS can do this, as can any dynamic loader. The other is some library that really cannot be safely loaded multiple times, because it depends on some lower-level shared resource. Such a library simply cannot be made safe without cooperation from the thing that controls that shared resource, because you cannot prevent a second copy of it being loaded by something you have no control over. If the - proposal were only about supporting the first of these applications, I would have far fewer objections to it. But it would have nothing to do with process-level scope, then. Ganesh ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Top Level -
On 2008 Aug 31, at 12:01, Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 11:20, Ganesh Sittampalam wrote: Where do the filehandle structures live in the latter case? The place you clearly think so little of that you need to ask: process-global (or process-local depending on how you think about it) storage. And everything in that storage must have locking. You'll have to look at specific implementations. One that I can think of off the top of my head is Perl 5's ithreads; there is a distinguished allocation store which is global to all ithreads, and the interpreter instance gives you primitives for locking and mutexing (see use threads::shared;). -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED] system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED] electrical and computer engineering, carnegie mellon universityKF8NH ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Compiler's bane
Ryan Ingram wrote: On Sun, Aug 31, 2008 at 12:46 AM, Andrew Coppin [EMAIL PROTECTED] wrote: Right. So if I have, say, the factorial function defined using the Y combinator, there's no way to stop the interpretter expanding an infinite number of copies of Y, even though in theory the factorial function should terminate? Well, this is exactly what ghci is doing; you just have to choose an evaluation order that makes sense. Lets consider a simple translation for recursive lets: let x = exp1 in exp2 (where x may be free in exp1 and/or exp2) Here's a simple translation into lambda-calculus: (\x. exp2) (y (\x. exp1)) (Of course, this representation for let can lose sharing; without knowing what you have or your goals I don't know if you care). Now, you just have to choose a y-combinator that makes sense for your evaluation order. If you do normal-order evaluation like Haskell (non-strict), this Y should work for you: y = \f. (\x. f (x x)) (\x. f (x x)) Oh well, I guess I'll just have to live with that one. Maybe I can make the binding to expand user-selectable or something... Now, if you are eagerly-expanding the entire expression, trying to get to head normal form, then any expression that ends up with y in it won't terminate. But if you use normal form evaluation order, then if a normal form exists, you will find it and terminate. So evaluating fact to normal form won't terminate, but evaluating fact 5 should. All of this strongly suggests that if you execute things in the correct order, you can arrange it so that expressions that have a normal form will be evaluated to it. But how to decide the correct evaluation order? For the plain lambda calculus, IIRC you just have to execute the left-most, outer-most redex every time and it'll work. For a language with let-binds, it is unclear to me how to proceed... ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Top Level -
On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 12:01, Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 11:20, Ganesh Sittampalam wrote: Where do the filehandle structures live in the latter case? The place you clearly think so little of that you need to ask: process-global (or process-local depending on how you think about it) storage. And everything in that storage must have locking. You'll have to look at specific implementations. One that I can think of off the top of my head is Perl 5's ithreads; there is a distinguished allocation store which is global to all ithreads, and the interpreter instance gives you primitives for locking and mutexing (see use threads::shared;). From what I can see from the source of this, it seems to rely on a global variable inside the Perl library that contains a pointer to the shared state area (actually a separate Perl interpreter of its own, but that's just an implementation detail). However I may be wrong as I was unable to fully figure out how the BOOT: mechanism works from a simple grep. I'm afraid I don't see how this generalises to sharing something across an entire process where the things that want to do the sharing are not in or controlled by the same shared library. In particular the filehandle structures required for buffered I/O need to be common to every single piece of code in the process that might want to use them, no matter what language or language implementation that code uses. Ganesh ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Compiler's bane
On Sun, 2008-08-31 at 17:29 +0100, Andrew Coppin wrote: Ryan Ingram wrote: On Sun, Aug 31, 2008 at 12:46 AM, Andrew Coppin [EMAIL PROTECTED] wrote: Right. So if I have, say, the factorial function defined using the Y combinator, there's no way to stop the interpretter expanding an infinite number of copies of Y, even though in theory the factorial function should terminate? Well, this is exactly what ghci is doing; you just have to choose an evaluation order that makes sense. Lets consider a simple translation for recursive lets: let x = exp1 in exp2 (where x may be free in exp1 and/or exp2) Here's a simple translation into lambda-calculus: (\x. exp2) (y (\x. exp1)) (Of course, this representation for let can lose sharing; without knowing what you have or your goals I don't know if you care). Now, you just have to choose a y-combinator that makes sense for your evaluation order. If you do normal-order evaluation like Haskell (non-strict), this Y should work for you: y = \f. (\x. f (x x)) (\x. f (x x)) Oh well, I guess I'll just have to live with that one. Maybe I can make the binding to expand user-selectable or something... Now, if you are eagerly-expanding the entire expression, trying to get to head normal form, then any expression that ends up with y in it won't terminate. But if you use normal form evaluation order, then if a normal form exists, you will find it and terminate. So evaluating fact to normal form won't terminate, but evaluating fact 5 should. All of this strongly suggests that if you execute things in the correct order, you can arrange it so that expressions that have a normal form will be evaluated to it. But how to decide the correct evaluation order? For the plain lambda calculus, IIRC you just have to execute the left-most, outer-most redex every time and it'll work. For a language with let-binds, it is unclear to me how to proceed... It depends on whether you want to preserve sharing or not. If not, you can use fix to de-sugar lambdas, and then de-sugar lets using the rule let x = e in f = (\ x - f) e and proceed as before. Or (again, if you don't care about sharing), you can descend recursively into the body of a let, remembering where the bindings were defined, and expand variables when you see them. Or keep an environment around, extend it on let, and if the left-most outermost redex is a variable, look it up. jcc ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Compiler's bane
On Sun, Aug 31, 2008 at 9:29 AM, Andrew Coppin [EMAIL PROTECTED] wrote: All of this strongly suggests that if you execute things in the correct order, you can arrange it so that expressions that have a normal form will be evaluated to it. But how to decide the correct evaluation order? For the plain lambda calculus, IIRC you just have to execute the left-most, outer-most redex every time and it'll work. For a language with let-binds, it is unclear to me how to proceed... What are you trying to get from the let binding? Sharing? The usual idea is that let represents heap allocation, and you evaluate the leftmost-outermost redex as usual, doing let substitution only when necessary to continue evaluation, and garbage-collecting bindings that no longer refer to variables in the current computation. You also make lambda-expressions create let-bindings during substitution to maximize sharing. Here's an example of how an interpreter could work: let fact_acc = \n x. (== n 0) x (fact_acc (- n 1) (* n x)) in fact_acc 3 1 The top-level redex is a let bind that is already in WHNF; if it wasn't, you continue evaluation inside of it. So instead you substitute and lose sharing because there are no other options. I'm going to leave all previous lets as ... in this evaluation to save typing: (substitute because leftmost-outermost redex is a let-bind) = let ... in (\n x. (== n 0) x (fact_acc (- n 1) (* n x))) 3 1 (beta, beta) = let ...; n0 = 3; x0 = 1 in (== n0 0) x0 (fact_acc (- n0 1) (* n0 x0)) (primitive == is strict, n0 is already in normal form, evaluate ==) = let ... in False x0 (fact_acc (- n0 1) (* n0 x0)) (False x y = y) = let ... in fact_acc (- n0 1) (* n0 x0) (substitute fact_acc, beta, beta) = let ...; n1 = (- n0 1); x0 = (* n0 x0) in (== n1 0) x1 (fact_acc (- n1 1) (* n1 x1)) (primitive == is strict, evaluate its argument. primitive - is strict, argument is in whnf, evaluate -) (This is a very important step; note that I am now evaluating inside of a let bind!) = let ...; n1 = 2; ... in (== n1 0) x1 (fact_acc (- n1 1) (* n1 x1)) (evaluate ==) = let ... in False x1 (fact_acc (- n1 1) (* n1 x1)) (False x y = y) = let ... in fact_acc (- n1 1) (* n1 x1) = let ...; n2 = (- n1 1); x2 = (* n1 x1) in (== n2 0) x2 (fact_acc (- n2 1) (* n2 x2)) = let ...; n2 = 1; ... in (== n2 0) x2 (fact_acc (- n2 1) (* n2 x2)) = let ... in False x2 (fact_acc (- n2 1) (* n2 x2)) = let ... in fact_acc (- n2 1) (* n2 x2)) = let ...; n3 = (- n2 1); x3 = (* n2 x2) in (== n3 0) x3 (fact_acc (- n3 1) (* n3 x3)) = let ...; n3 = 0; ... in (== n3 0) x3 (fact_acc (- n3 1) (* n3 x3)) = let ... in True x3 (fact_acc (- n3 1) (* n3 x3)) = let ... in x3 (We can garbage collect fact_acc and n3 here) = let n0 = 3; x0 = 1; n1 = 2; x1 = (* n0 x0); n2 = 1; x2 = (* n1 x1); x3 = (* n2 x2) in x3 (primitive * is strict, so we get a big spine of evaluating x3 which requires x2 which requires x1 which requires x0 which is finally already in head normal form) = let ...; x1 = (* 3 1); x2 = (* 2 x1); x3 = (* 1 x2) in x3 (garbage collect n0, n1, n2, n3) = let x1 = 3; x2 = (* 2 x1); x3 = (* 1 x2) in x3 (substitute garbage collect x1) = let x2 = (* 2 3); x3 = (* 1 x2) in x3 = let x2 = 6; x3 = (* 1 x3) in x3 = let x3 = (* 1 6) in x3 = let x3 = 6 in x3 = 6 Does this seem like something you could do? -- ryan ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] language proposal: ad-hoc overloading
The point of having a strongly typed language is so the compiler can do more work for you. But right now I do a lot of typing (pun not intended) to appease the compiler. Let me give you an example: module Prob where import qualified Data.Map as M ... newtype Prob p a = Prob { runProb :: [(a,p)] } combine :: (Num p, Ord a) = Prob p a - Prob p a combine m = Prob $ M.assocs $ foldl' (flip $ uncurry $ M.insertWith (+)) M.empty $ runProb m Do you see it? All those M. just seem dirty to me, especially because the compiler should be able to deduce them from the types of the arguments. My proposal is to allow ad-hoc overloading of names; if a name is ambiguous in a scope, attempt to type-check the expression against each name. It is only an error if type-checking against all names fails. If type-checking succeeds for more than one then the expression is ambiguous and this is also an error. Pros: shorter code, less busywork to please the compiler Cons: potentially exponential compile time? Any thoughts? -- ryan ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Compiler Construction course using Haskell?
Dear Johannes, Besides the IPT course, we also teach a course hat used to be called grammars and parsing. This course is taken before the compiler construction course. In this course we deal with parser combinators, datatypes, folds, first and follow, LL(1), and some more stuff, all in Haskell. The lecture notes are available from the webpage for the course: http://www.cs.uu.nl/docs/vakken/gont/literatuur.html The web page is in Dutch, but the lecture notes are in English. All the best, Johan On 20 Aug 2008, at 21:47, Johannes Waldmann wrote: Thanks for all the pointers. This is very useful. On parsers: yes, LL/LR theory and table-based parsers have been developed for a reason and it's no easy decision to throw them out. Still, even Parsec kind of computes the FIRST sets? And - I positively hate preprocessors. I really want my domain specific languages embedded because I want to use Haskell's types, functions, modules etc. for the domain specific objects (parsers, AST walkers, etc.) Best regards, J.W. ___ 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] language proposal: ad-hoc overloading
Am Sonntag, 31. August 2008 20:21 schrieb Ryan Ingram: The point of having a strongly typed language is so the compiler can do more work for you. But right now I do a lot of typing (pun not intended) to appease the compiler. Let me give you an example: module Prob where import qualified Data.Map as M ... newtype Prob p a = Prob { runProb :: [(a,p)] } combine :: (Num p, Ord a) = Prob p a - Prob p a combine m = Prob $ M.assocs $ foldl' (flip $ uncurry $ M.insertWith (+)) M.empty $ runProb m Do you see it? All those M. just seem dirty to me, especially because the compiler should be able to deduce them from the types of the arguments. My proposal is to allow ad-hoc overloading of names; if a name is ambiguous in a scope, attempt to type-check the expression against each name. It is only an error if type-checking against all names fails. If type-checking succeeds for more than one then the expression is ambiguous and this is also an error. Pros: shorter code, less busywork to please the compiler Cons: potentially exponential compile time? Any thoughts? -- ryan Another Con is that the compiler can catch fewer programming errors that way. I can't think of a credible example right now, but what if you typo'd a function argument, it typechecks according to the above rules, but with a completely unintended function and your programme outputs garbage (of course, garbage which is not immediately recognisable as such)? Still, I often have the same desire when I forget a qualification :) Cheers, Daniel ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
My proposal is to allow ad-hoc overloading of names; +1, although ... this could interact badly with the (still common?) practice of leaving out type declarations. (of course having allowed this in the first place is another language design error :-) when considering language changes (extensions), we should carefully distinguish whether it mainly helps readability or writability - and readability should be the prime concern. e.g. ad-hoc overloading will lead to less typing, but more trouble reading. often, the work of typing can be reduced by tools (e.g. IDEs that know about the names that are currently in scope, and are applicable for a particular type, and can auto-complete them etc.) in the particular case of writing M.* too often, another option would be to have a local unqualification of an import. Cf. C++: using namespace, which can occur in any scope, not just at top (module) level; or Ada: use. J.W. signature.asc Description: OpenPGP digital signature ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
Hello Ryan, Sunday, August 31, 2008, 10:21:44 PM, you wrote: Cons: potentially exponential compile time? yes, and exponential programming complexity growth, going to brain explosion :) don't forget that OOP languages that supports ad-hoc overloading doesn't allow to infer types in both directions. it seems that we should trade one feature for another -- Best regards, Bulatmailto:[EMAIL PROTECTED] ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Compiler's bane
Ryan Ingram wrote: What are you trying to get from the let binding? Sharing? Convinience. let x = foo in bar is so much easier to write than (\x - bar) foo when foo and/or bar is large. Trouble is, as soon as you allow let-bindings, some clever person is going to start writing recursive ones. And actually, that's a useful thing to be able to do, but it makes figuring out the technical details... rather nontrivial. (Seriously, I had no idea I was going to get into this much trouble!) The usual idea is that let represents heap allocation, and you evaluate the leftmost-outermost redex as usual, doing let substitution only when necessary to continue evaluation, and garbage-collecting bindings that no longer refer to variables in the current computation Right. So ignore the let-bindings unless the redex of interest is a let-bound variable? That sounds reasonably easy... ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
On 2008 Aug 31, at 14:58, Daniel Fischer wrote: Am Sonntag, 31. August 2008 20:21 schrieb Ryan Ingram: Do you see it? All those M. just seem dirty to me, especially because the compiler should be able to deduce them from the types of the arguments. Another Con is that the compiler can catch fewer programming errors that way. If omitting the qualifier doesn't cause this already then I don't think it will be much of a problem (either it won't find what you're looking for or it will be ambiguous). -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED] system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED] electrical and computer engineering, carnegie mellon universityKF8NH ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
Well, I was thinking that way when I was starting learning Haskell. But then I realized that this feature would make code much harder to read. Suppose you have different thing all named insertWith. You've got one somewhere in your program; how do YOU know when looking at the code after a month or so, which one is this? Certainly, given a smart IDE you can ask it; but I think that code should be clear just when you look at it, without any action. What CAN be useful is, IMHO, to make your IDE substitute this M.s for you when you type. On 31 Aug 2008, at 22:21, Ryan Ingram wrote: The point of having a strongly typed language is so the compiler can do more work for you. But right now I do a lot of typing (pun not intended) to appease the compiler. Let me give you an example: module Prob where import qualified Data.Map as M ... newtype Prob p a = Prob { runProb :: [(a,p)] } combine :: (Num p, Ord a) = Prob p a - Prob p a combine m = Prob $ M.assocs $ foldl' (flip $ uncurry $ M.insertWith (+)) M.empty $ runProb m Do you see it? All those M. just seem dirty to me, especially because the compiler should be able to deduce them from the types of the arguments. My proposal is to allow ad-hoc overloading of names; if a name is ambiguous in a scope, attempt to type-check the expression against each name. It is only an error if type-checking against all names fails. If type-checking succeeds for more than one then the expression is ambiguous and this is also an error. Pros: shorter code, less busywork to please the compiler Cons: potentially exponential compile time? Any thoughts? -- ryan ___ 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] language proposal: ad-hoc overloading
Ryan Ingram wrote: My proposal is to allow ad-hoc overloading of names; if a name is ambiguous in a scope, attempt to type-check the expression against each name. It is only an error if type-checking against all names fails. If type-checking succeeds for more than one then the expression is ambiguous and this is also an error. Pros: shorter code, less busywork to please the compiler Cons: potentially exponential compile time? Any thoughts? Now try importing something like Data.Map where almost every single function name clashes with the Prelude. If I write foo x = map (bar x) then unless there are some explicit type signatures somewhere, the poor compiler has no way of knowing whether this function is mapping over a list or a Map. (Arguably you might wish to write a function that does both. This quickly boils down to an argument along the lines of Haskell doesn't support container neutrality very well, which as I understand it is already a known problem.) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
On 2008.08.31 11:21:44 -0700, Ryan Ingram [EMAIL PROTECTED] scribbled 1.0K characters: The point of having a strongly typed language is so the compiler can do more work for you. But right now I do a lot of typing (pun not intended) to appease the compiler. Let me give you an example: module Prob where import qualified Data.Map as M newtype Prob p a = Prob { runProb :: [(a,p)] } combine :: (Num p, Ord a) = Prob p a - Prob p a combine m = Prob $ M.assocs $ foldl' (flip $ uncurry $ M.insertWith (+)) M.empty $ runProb m Do you see it? All those M. just seem dirty to me, especially because the compiler should be able to deduce them from the types of the arguments. My proposal is to allow ad-hoc overloading of names; if a name is ambiguous in a scope, attempt to type-check the expression against each name. It is only an error if type-checking against all names fails. If type-checking succeeds for more than one then the expression is ambiguous and this is also an error. Pros: shorter code, less busywork to please the compiler Cons: potentially exponential compile time? Any thoughts? -- ryan I think this would be very nice in GHCi, because there the situation is even *worse*. I think we've all experienced importing Data.Map or Data.ByteString and discovering we need to tediously write it out in *full*, because we can't even do qualified imports of it! -- gwern BND fritz FKS 1071 Face government Tomahawk DREO IA O signature.asc Description: Digital signature ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
Gwern Branwen wrote: I think this would be very nice in GHCi, because there the situation is even *worse*. I think we've all experienced importing Data.Map or Data.ByteString and discovering we need to tediously write it out in *full*, because we can't even do qualified imports of it! Amen to that! Data.ByteString.Lazy.pack Hello Data.ByteString.Lazy.++ Data.ByteString.Lazy.pack World! ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Cleaning up the Debian act (report from the trenches)
On Wed, Aug 27, 2008 at 10:20 PM, David Bremner [EMAIL PROTECTED] wrote: Ketil Malde wrote: Another Debian question, once I've populated the debian/ directory one way or another, how should this be integrated with the rest of the project? Should it be part of the darcs archive, or a separate archive (foo-debian), or what? How do people organize this? [EMAIL PROTECTED] is a good place for generic debian packaging questions. After you have a package which works, and which hopefully lintian (a tool for checking debian packages) does not complain about, you can ask on debian-mentors for a sponsor, who will check over the package and hopefully upload it. Right now there is not too much interest in uploading new packages, because people are trying to get lenny out the door. I've personally had _very_ limited success in getting any haskell packages (both libs and apps) to attract any interest on debian-mentors. This is very unfortunate. I suspect this is due to haskell being an unknown language to most people on that list, and I also suspect that the rather strict (but completely called for) rules about dependencies and versions for haskell packages are unknown to most DDs. I've long thought that the DDs who are on debian-haskell are in an excellent position to change all of this, but I've never pushed very much on this. I've only ever gotten a single comment on an RFS for a haskell package. The comment was scary looking package (http://lists.debian.org/debian-mentors/2007/10/msg00389.html). AFAICS there is great room for improvement here, but this conversation should probably move to debian-haskell or debian-mentor... /M ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
Erm... Why can't we? On 1 Sep 2008, at 00:43, Gwern Branwen wrote: I think we've all experienced importing Data.Map or Data.ByteString and discovering we need to tediously write it out in *full*, because we can't even do qualified imports of it! -- gwern BND fritz FKS 1071 Face government Tomahawk DREO IA O ___ 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] language proposal: ad-hoc overloading
Oh, sorry, haven't noticed you said ghcI. On 1 Sep 2008, at 00:59, Miguel Mitrofanov wrote: Erm... Why can't we? On 1 Sep 2008, at 00:43, Gwern Branwen wrote: I think we've all experienced importing Data.Map or Data.ByteString and discovering we need to tediously write it out in *full*, because we can't even do qualified imports of it! -- gwern BND fritz FKS 1071 Face government Tomahawk DREO IA O ___ 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] language proposal: ad-hoc overloading
On 2008.09.01 01:01:21 +0400, Miguel Mitrofanov [EMAIL PROTECTED] scribbled 0.5K characters: Oh, sorry, haven't noticed you said ghcI. On 1 Sep 2008, at 00:59, Miguel Mitrofanov wrote: Erm... Why can't we? The GHC API just doesn't support it. See the bug report filed on this issue: http://hackage.haskell.org/trac/ghc/ticket/1895. (Remember, each cc is like a vote!) -- gwern RX-7 PGP 5.0i ISFR Kosiura Reuters WANK mailbomb Templar NATIA signature.asc Description: Digital signature ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
Miguel Mitrofanov wrote: Suppose you have different thing all named insertWith. You've got one somewhere in your program; how do YOU know when looking at the code after a month or so, which one is this? We already have that situation when classes are involved. If you replace specialised functions by abstractions provided classes, for instance mempty instead of Data.Structure.empty fmap instead of Data.Structure.map folds from Data.Foldable instead of a specialised module There certainly are more examples, but these are the most common. IMHO this doesn't make code much harder to read. mempty gives us some empty data structre, fmap applies a function to all its elements and folds do the same. It doesn't matter if we're talking about lists, sets or something else. And it has the huge advantage that you can replace a data structure by another (Maybe by [], [] by Set, ...) simply by changing a type signature and not the code. Certainly, given a smart IDE you can ask it; but I think that code should be clear just when you look at it, without any action. I think that - at least in the examples listed above - the code remains very clear. [...] Regards, Stephan -- Früher hieß es ja: Ich denke, also bin ich. Heute weiß man: Es geht auch so. - Dieter Nuhr ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Compiler's bane
2008/9/1 Andrew Coppin [EMAIL PROTECTED]: Ryan Ingram wrote: What are you trying to get from the let binding? Sharing? Convinience. let x = foo in bar is so much easier to write than (\x - bar) foo when foo and/or bar is large. Trouble is, as soon as you allow let-bindings, some clever person is going to start writing recursive ones. And actually, that's a useful thing to be able to do, but it makes figuring out the technical details... rather nontrivial. (Seriously, I had no idea I was going to get into this much trouble!) I'm confused -- why is this different to having recursive top-level bindings? Jeremy ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Re: [Haskell] Top Level -
Ganesh Sittampalam wrote: On Sat, 30 Aug 2008, Ashley Yakeley wrote: OK. Let's call it top-level scope. Haskell naturally defines such a thing, regardless of processes and processors. Each top-level - would run at most once in top-level scope. If you had two Haskell runtimes call by C code, each would have its own memory allocator and GC; IORefs, Uniques and thunks cannot be shared between them; and each would have its own top-level scope, even though they're in the same process. That sounds more feasible - though it does constrain a plugin architecture (in which Haskell code can dynamically load other Haskell code) to cooperate with the loading RTS and not load multiple copies of modules; this might make linking tricky. This is a good idea anyway. It's up to the dynamic loading architecture to get this right. There's also the problem Duncan Coutts mentioned about loading multiple versions of the same module - what are the semantics of - in relation to that? If they are different versions, they ought to be considered different modules with different names. Thus, Unique in base-3.0.2.0 ought to be a different type than Unique in base-4.0. Thus any top-level initialisers ought to be considered different and be run separately. What's the current static behaviour? What happens if I link with packages B C, which link with different versions of A? Also, it's no use for mediating access to a resource or library that can only be accessed once, right? In fact, even without the problem of two Haskell runtimes in one process this can't work, since some library in another language might also choose to access that resource or library. What applications does this leave beyond Data.Unique and Random? So far we've just looked at declaring top-level IORefs and MVars. By declaring top-level values of type IOWitness, you can generate open witnesses to any type, and thus solve the expression problem. See my open witness library and paper: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/open-witness http://semantic.org/stuff/Open-Witnesses.pdf -- Ashley Yakeley ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
Well, I was thinking that way when I was starting learning Haskell. But then I realized that this feature would make code much harder to read. Suppose you have different thing all named insertWith. You've got one somewhere in your program; how do YOU know when looking at the code after a month or so, which one is this? Certainly, given a smart IDE you can ask it; but I think that code should be clear just when you look at it, without any action. Indeed. Too much overloading can be a lot of trouble. You can do adhoc overloading already: {-# LANGUAGE FlexibleInstances #-} class Adhoc a where adhoc :: a instance Adhoc ((a-b)-([a]-[b])) where adhoc = map instance Adhoc (Maybe a-a) where adhoc = maybe (error wrong number) id instance Adhoc [Char] where adhoc = hello, world instance Adhoc (String-IO ()) where adhoc = print main :: IO () main = adhoc (adhoc (adhoc . Just :: Char - Char) (adhoc :: String) :: String) I hope this also demonstrates why it is usually a bad idea, even if it often looks good in theory. If you're not convinced yet, play with this kind of code in practice. The well-typed programs don't go wrong of static type checking depends on a clear separation of right and wrong. If your use of types allows anything to be a valid program, minor variations in code will no longer be caught by the type system: at best, you'll get missing instance, more likely you'll get too many possibilities, and at worst, the code will simply do something different. What CAN be useful is, IMHO, to make your IDE substitute this M.s for you when you type. haskellmode for Vim does that (though it isn't type aware, so you get a larger menu of possible completions than necessary). Claus [1] http://www.cs.kent.ac.uk/~cr3/toolbox/haskell/Vim/ ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ANN: vxml (validating xml lib) - maybe usable now, quadratic compilation time ?
Oleg has pointed me into the right direction: He has suggested to use kind of class AttrOk elTrype attr for attributes (result 35s - 30s) and do something similar with the state. (30s - 4,5s). After doing this I was quite happy: The 4,5s do include reading the dtd and generating about 1500 DecQ declarations. There might still be some duplication.. in state transformation steps. However trying to typecheck the same file repeating the body 400 times didn't end.. why? Have a quick glance at the file data which shows quadratic behaviour. That's bad.. I would like to have some linear behaviour. Any ideas what is causing this? Is there a way to get linear scalability? However disabling all validation stuff (see cabal flag) no longer improves performance much. The data below proofs that right now validation increases compilation time by a factor 1.35- 1.45 (within the range of 5-30 replications of the body) If you'd like to play with the library and give some feedback I'd be happy. Read the README. The benchpress dependency is only needed for this benchmark test. You may want to remove it from the cabal file. So don't try to compile 4000 lines long xml files or be prepared to wait days. I should expand the benchmark to also offer results for xhtml lib. Sincerly Marc Weber = compilation times with validation == body replication count | compilation time [ms] 1 4146.477 2 4292.153 3 4508.56 4 4654.2441 5 4788.195 6 5041.6749 7 5347.11405 8 6134.59605 9 6019.6241 10 6459.544 11 7054.4339 12 7614.197 13 8489.003 14 8529.6109 15 9271.491 16 10058.419 17 12290.142 18 13736.0749 19 14863.893 20 15944.82 21 17856.6117 22 17977.841 23 17686.297 24 19279.314 25 20960.785 26 22750.754 27 24407.506 28 26342.242 29 28423.79 30 30932.7772 31 48478.841 32 45609.897 33 40574.255 34 41220.062 35 43952.5455 36 47437.922 37 50584.1210001 38 53983.8485 39 57935.593 = === eg starting gnuplot entering f(x)=(x-b)**2*c+a fit f(x) 'data' via a, b, c plot 'data', f(x) = compilation times without validation body replication count | compilation time [ms] 1 3939.887 Import.hs has been recompiled. thats why the first took longer then the next 2 3138.127 3 3080.317 4 3179.19 5 3279.339 6 3604.609 7 3736.829 8 4094.61795 9 4252.377 10 4767.588 11 5070.188 12 5537.007 13 5840.085 14 6478.276 15 6916.67 16 7568.444 17 8301.047 18 9211.3689 19 10025.886 20 10872.749 21 12086.263 22 12975.372 23 14366.282 24 15640.214 = === ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Top Level -
On 2008 Aug 31, at 13:20, Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 12:01, Ganesh Sittampalam wrote: On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 11:20, Ganesh Sittampalam wrote: Where do the filehandle structures live in the latter case? The place you clearly think so little of that you need to ask: process-global (or process-local depending on how you think about it) storage. And everything in that storage must have locking. You'll have to look at specific implementations. One that I can think of off the top of my head is Perl 5's ithreads; there is a distinguished allocation store which is global to all ithreads, and the interpreter instance gives you primitives for locking and mutexing (see use threads::shared;). I'm afraid I don't see how this generalises to sharing something across an entire process where the things that want to do the sharing are not in or controlled by the same shared library. In particular the filehandle structures required for buffered I/O need to be common to every single piece of code in the process that might want to use them, no matter what language or language implementation that code uses. For that you probably want to look at how ld.so.1 and libc interact to share the malloc pool and the stdin/stdout/stderr, among others. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED] system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED] electrical and computer engineering, carnegie mellon universityKF8NH ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
On Sun, Aug 31, 2008 at 2:10 PM, Claus Reinke [EMAIL PROTECTED] wrote: Indeed. Too much overloading can be a lot of trouble. You can do adhoc overloading already: {-# LANGUAGE FlexibleInstances #-} class Adhoc a where adhoc :: a instance Adhoc ((a-b)-([a]-[b])) where adhoc = map instance Adhoc (Maybe a-a) where adhoc = maybe (error wrong number) id instance Adhoc [Char] where adhoc = hello, world instance Adhoc (String-IO ()) where adhoc = print Yes, of course taken to this extent it is bad, but I'm not suggesting this at all. In particular, we have well-chosen names for many functions, but not every container can use exact same interface (see, for example, the many discussions on restricted monads). So we can't reuse the same function name for similar concepts that have slightly different interfaces. main :: IO () main = adhoc (adhoc (adhoc . Just :: Char - Char) (adhoc :: String) :: String) I hope this also demonstrates why it is usually a bad idea, even if it often looks good in theory. If you're not convinced yet, play with this kind of code in practice. I do play with this kind of code in practice, in other languages. In practice, I don't see the kind of problems you are bringing up occur. However, those languages tend to be dynamically typed so I do get the occasional runtime type error. I'd much rather have a safe way of doing less typing than an unsafe way. As an example of this done correctly, in Ruby, you have Array#each: [1,2,3].each { |x| print x } Hash#each: { :foo = hello, :bar = world }.each { |k, v| print v } etc. each corresponds to the idea of iterating over a container (foldM in Haskell) without being a slave to maintaining an identical API for each type. I maintain that in Haskell, trying to get this same generality often leads to abuse of the typeclass system for things where the types should trivially be determined at compile time. The well-typed programs don't go wrong of static type checking depends on a clear separation of right and wrong. If your use of types allows anything to be a valid program, minor variations in code will no longer be caught by the type system: at best, you'll get missing instance, more likely you'll get too many possibilities, and at worst, the code will simply do something different. I don't think this is a strong argument. In practice most things have a single concrete type and helping the compiler with extra qualified names is just meaningless typing. I'm suggesting that in the case of this code: import Data.Map as M x = map (+1) M.empty map should be inferred as M.map instead of being ambiguous. There's already some minor work in the direction I am suggesting in record syntax, but it only works during pattern matching. I'd like cx foo + cy foo to work on any foo that has record members cx and cy that are members of Num, instead of needing to preface every record with the datatype name to avoid ambiguity. In particular I do NOT want each function in its own typeclass; the previous post saying: foo x = map (bar x) should be rejected as ambiguous without a type signature somewhere (at least, if Data.Map is imported). This does give some amount of action at a distance where changing a file that is imported by another file can cause previously unambiguous code to become ambiguous, but that is already true! And this modification would make it less likely to be the case. As to the argument that a sufficiently smart IDE would insert the M. for me, I think that is flawed. First, there isn't a sufficiently smart IDE yet, and second, it'd be better for the type-aware IDE to tell me the types of things when I (for example) mouse over them, instead of helping me type longer things. -- ryan ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
On Sun, 2008-08-31 at 16:08 -0700, Ryan Ingram wrote: In particular I do NOT want each function in its own typeclass; the previous post saying: foo x = map (bar x) should be rejected as ambiguous without a type signature somewhere What type signature do you propose? It seems as if you're proposing that doubleSet :: Set.Set Int - Set.Set Int doubleSet = map (*2) doubleList :: [Int] - [Int] doubleList :: map (*2) work, but that you not be allowed to notice that the definitions are identical and substitute double = map (*2) for both definitions. Sorry, but I use Haskell specifically because I do *not* want to use C ++. jcc ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
As to the argument that a sufficiently smart IDE would insert the M. for me, I think that is flawed. First, there isn't a sufficiently smart IDE yet, I do believe there will be. What we do now is sort of putting down requirements ... and second, it'd be better for the type-aware IDE to tell me the types of things when I (for example) mouse over them, instead of helping me type longer things. That's been said before: an IDE might help in writing/changing code, but code should be readable without tool support. J.W. signature.asc Description: OpenPGP digital signature ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
2008/8/31 Ryan Ingram [EMAIL PROTECTED]: My proposal is to allow ad-hoc overloading of names; if a name is ambiguous in a scope, attempt to type-check the expression against each name. It is only an error if type-checking against all names fails. If type-checking succeeds for more than one then the expression is ambiguous and this is also an error. -1, at least for now. Haskell already has one method of overloading: type classes. What you propose is a seemingly innocent extension that I now doubt has extremely far-reaching consequences into the language. Such a feature should be properly researched before it is added to the language. Here's an example of such a concern: you write the following: import Data.Map foo = map What is the type of `foo'? I can think of several solutions to this problem: one that springs to mind is to create something akin to an on-the-fly typeclass class HasMap h where map :: h and add instances for [a] and Ord k = Map k a. But I suspect there are other options, with differing semantics. What if you further define bar = map (+1), what happens then? Etc. etc. The point I'm trying to make is that such a seemingly simple change is in actual fact not nearly as simple as you might expect. So we should consider carefully how this changes the language, and whether it's worth it. -- -David ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
Oops, forgot to send to list. On Mon, 2008-09-01 at 01:27 +0100, Philippa Cowderoy wrote: On Mon, 2008-09-01 at 01:11 +0100, David House wrote: 2008/8/31 Ryan Ingram [EMAIL PROTECTED]: My proposal is to allow ad-hoc overloading of names; if a name is ambiguous in a scope, attempt to type-check the expression against each name. It is only an error if type-checking against all names fails. If type-checking succeeds for more than one then the expression is ambiguous and this is also an error. -1, at least for now. Haskell already has one method of overloading: type classes. What you propose is a seemingly innocent extension that I now doubt has extremely far-reaching consequences into the language. Such a feature should be properly researched before it is added to the language. Here's an example of such a concern: you write the following: import Data.Map foo = map What is the type of `foo'? If I've understood the proposal, that wouldn't check unless foo was used in a way (within the module) that makes it clear which of Prelude.map or Data.Map.map to use and uses it consistently. So if that's the entire module, it wouldn't check. I'm still not keen, but in a sense the idea here is to avoid this variety of overloading leaking into the type system itself: it could be implemented (extremely naively) as typecheck with each possible permutation for resolving the overloading, use any unique solution or fail if there isn't one. -- Philippa Cowderoy [EMAIL PROTECTED] ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
On Sun, Aug 31, 2008 at 4:21 PM, Jonathan Cast [EMAIL PROTECTED] wrote: It seems as if you're proposing that doubleSet :: Set.Set Int - Set.Set Int doubleSet = map (*2) doubleList :: [Int] - [Int] doubleList :: map (*2) work, but that you not be allowed to notice that the definitions are identical and substitute double = map (*2) for both definitions. Yes, that's exactly what I am suggesting. This is especially important because Set cannot be made an instance of Functor because of the Ord restriction on the elements, so you can't generalize to fmap without redefining Functor as RestrictedFunctor or some such, which adds a ton of additional type-level programming that shouldn't be required for day-to-day work. I'm not against being able to use double = map (*2) generally, but the evidence I've seen says that the PL theory isn't there yet to do so without unacceptable performance penalties. (That definition violates the monomorphism restriction anyways). Sorry, but I use Haskell specifically because I do *not* want to use C++. I don't think a language I dislike also has this feature is a good argument against a feature. C++ also has named fields in records, and a standard I/O library. Should Haskell not have those either? -- ryan ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
On Sun, Aug 31, 2008 at 5:11 PM, David House [EMAIL PROTECTED] wrote: Here's an example of such a concern: you write the following: module Amb where import Data.Map foo = map What is the type of `foo'? Exactly the same as now: it has no type: amb.hs:4:6: Ambiguous occurrence `map' It could refer to either `Prelude.map', imported from Prelude or `Data.Map.map', imported from Data.Map at amb.hs:2:0-14 On the other hand, this module would no longer fail to compile: module Amb where import Data.Map foo :: (a - b) - [a] - [b] foo = map which right now gives the same error message as above, but with my proposal would successfully compile, with foo = Prelude.map. As Philippa said, the naive implementation is: 1) Attempt to typecheck with all permutations of ambiguous names 2a) If zero permutations typecheck, type error. 2b) If multiple permutations typecheck, the program is ambiguous (current behavior) 2c) Otherwise, exactly one typechecks successfully. Specialize the ambiguous names to the chose permutation and continue compilation. It is a conservative extension of the language, because any program that successfully compiles now has no change: there are no ambiguous names in any currently compiling Haskell program. But it accepts some additional programs that have ambiguities, by choosing the only result that typechecks. If there is more than one possible type for foo, the program is still ambiguous and therefore should not compile. -- ryan ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
On Sun, Aug 31, 2008 at 11:21:44AM -0700, Ryan Ingram wrote: [..] Any thoughts? -- ryan Nice problem, nice idea.. Maybe the time is better spend on IDEs than extending the (or all) compilers.. Right now I've something like this in my vim script files: function! vl#dev#haskell#qffixfixable#AddMissingExtensions() let addExt='' let alreadyAsked = {} for qfitem in reverse(getqflist()) let match = matchstr(qfitem['text'] \ , '(use -X\zs[^)]*\ze)\|(-X\zs[^ ]*\ze permits this)\|(Use \zs[^ ]*\ze to lift this restriction)' \ .'\|(Use -X\zs[^ ]*\ze to allow operators in types)' \ .'\|(Use -X\zs[^ ]*\ze to suppress this message)' \ .'\|Use -X\zs[^ ]*\ze if you want to disable this' \ .'\|Use -X\zs[^ ]*\ze to permit this' \ .'\|(Use -X\zs[^ ]*\ze to allow multi-parameter classes)' \ .'\|([Uu]se -X\zs[^ ]*\ze)' \ .'\|or use \zs[^ ]*\ze' \ .'\|(Use \zs[^ ]*\ze to permit this)' \ .'\|Use -X\zs[^ ]*\ze to permit it' \ .'\|Use -X\zs[^ ]*\ze if you want to allow more.)' \ ) let replace = { \ '-fno-monomorphism-restriction' : 'NoMonomorphismRestriction' \ , '-fallow-undecidable-instances' : 'UndecidableInstances' \ } let match = get(replace, match, match) if match != '' let addExt = match endif getting many information out of error message asking me wether I want to add the used extension to the {#- LANGUAGE .. #-} pragma. So what about enhancing ghc so that it prints a message such as = hs file === import qualified Data.Set as S import qualified Data.Map as M [..] = error message == file.hs: line col: not in scope foo. Maybe you meant M.empty or S.empty or without qualified file.hs: line col: ambiguous occurence of empty, Maybe you meant M.empty or S.empty then it woulde be easy to ask the editor to do the right thing, give you a choice ? I'd say this is not as perfect as your proposal, but it can be implemented much more easily. Sincerly Marc Weber ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] language proposal: ad-hoc overloading
On Sun, 2008-08-31 at 19:06 -0700, Ryan Ingram wrote: On Sun, Aug 31, 2008 at 4:21 PM, Jonathan Cast [EMAIL PROTECTED] wrote: It seems as if you're proposing that doubleSet :: Set.Set Int - Set.Set Int doubleSet = map (*2) doubleList :: [Int] - [Int] doubleList :: map (*2) work, but that you not be allowed to notice that the definitions are identical and substitute double = map (*2) for both definitions. Yes, that's exactly what I am suggesting. This is especially important because Set cannot be made an instance of Functor because of the Ord restriction on the elements, so you can't generalize to fmap without redefining Functor as RestrictedFunctor or some such, which adds a ton of additional type-level programming that shouldn't be required for day-to-day work. This concept of `day-to-day work' is a curious one. Haskell is not a mature language, and probably shouldn't ever be one. There will always be new discoveries in purely functional programming, and as the art advances, features like this ad-hoc overloading hack (and ACIO) will become obsolete and have to be thrown over-board. I'd rather (much rather!) people concerned with day-to-day programming for writing programs people actually use incorporate Haskell's features into other, more practical, languages (as those who *actually* care about such things are) rather than incorporating features from day-to-day production languages into Haskell. I'm not against being able to use double = map (*2) generally, but the evidence I've seen says that the PL theory isn't there yet to do so without unacceptable performance penalties. I don't believe in ``unacceptable performance penalties'' as a design criterion for Haskell. This is supposed to be a /research/ language. (That definition violates the monomorphism restriction anyways). So? Sorry, but I use Haskell specifically because I do *not* want to use C++. I don't think a language I dislike also has this feature How about ``a language I dislike specifically (among other things) because of this `feature' also has this feature'? The great problem with C++ is that ad-hoc overloading allows operators to be defined in an ad-hoc way. In fact, C++ is now adding a feature similar to Haskell's type classes, in an attempt to reign ad-hoc overloading in. I don't thing Haskell should be trying to unreign ad-hoc overloading instead. is a good argument against a feature. C++ also has named fields in records, and a standard I/O library. Should Haskell not have those either? Standard I/O libraries are a bad idea, yes, and C++'s implementation of named fields has the same problem --- lack of principle types --- as its ad-hoc overloading. So sure, I'd oppose Haskell introducing either. jcc ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ANN: vxml (validating xml lib) - maybe usable now, quadratic compilation time ?
There might still be some duplication.. in state transformation steps. I've removed duplicate state machine paths. Instead of approxmiately 1500 there are only 500 left. You can see the impact on speed here http://mawercer.de/~marc/vxml.svg data + (red): approx 1500 data3 * (blue): approx 500 (current version) data2 x (green): without validation So most time is now spend somwhere else. Sincerly Marc Weber ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Top Level -
On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote: On 2008 Aug 31, at 13:20, Ganesh Sittampalam wrote: I'm afraid I don't see how this generalises to sharing something across an entire process where the things that want to do the sharing are not in or controlled by the same shared library. In particular the filehandle structures required for buffered I/O need to be common to every single piece of code in the process that might want to use them, no matter what language or language implementation that code uses. For that you probably want to look at how ld.so.1 and libc interact to share the malloc pool and the stdin/stdout/stderr, among others. If buffered IO is handled by libc rather than by specific language runtimes, then the same mechanism of using global variables inside libc would work fine; but this technique doesn't extend to providing process-scope shared state for library code that might be loaded multiple times with no knowledge of the other instances. Ganesh ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe