Re: [Haskell-cafe] Just for a laugh...
David Roundy wrote: On Fri, Jun 01, 2007 at 07:39:32PM +0100, Andrew Coppin wrote: No, I mean... how could you use unsafePerformIO to perform a typecast? I don't see a way to do that. Then I'm confused. What typecast are you talking about? cast :: a - b cast x = unsafePerformIO (do writeIORef r x; readIORef r) where r = unsafePerformIO (newIORef undefined) The problem is that the Hindley/Milner type inference algorithm is unsound in the presence of effects - r may not be given polymorphic type. That's exactly the reason for ML's dreaded value restriction. - Andreas ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Trouble with record syntax and classes
[EMAIL PROTECTED] wrote: When you type class Foo in Java or C++, it does three things: 1. It declares a new type called Foo. 2. It declares a _set_ of types (i.e. a class). 3. It declares that the type Foo (and all of its subtypes) is a member of the set of types Foo. I would add: 4. Define a namespace, also called Foo, for a set of values (and probably nested classes). In Haskell, these three operations are distinct. 1. You declare a new type using data or newtype. 2. You declare a new set of types using class. 3. You declare that a type is a member of a class using instance. 4. You define a new namespace using module. Cheers, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Getting my feet wet - not in Haskell though
Joachim Durchholz wrote: I'll move on to the alternatives - Alice ML and/or Clean. Both can serialize without forcing lazy subexpressions. I don't know about Clean, but with respect to Alice ML this is not correct: Alice ML uniformly blocks on futures upon pickling, including lazy ones. Sometimes you may want to pickle lazy suspensions as such, but more often it is not what you want. In particular, the suspension can easily be larger than its result, and the closure may contain resources which cannot be pickled. If such a suspension was produced by an abstraction you may even argue that making contained resources observable partially breaks the abstraction. To adhere to uniformity, strong abstraction, and the Principle of Least Surprise, we thus chose to force lazy futures in Alice ML. No FUD, please ;-) And yes I know there are devils lurking in every language and environment. I'm pretty sure that Haskell has a few others to offer, too. (There's still no good introduction to Monads, for example. One that's understandable for a programmer who knows his Dijkstra well but no category theory. And a few other things.) No FUD, please ;-) ;-) Cheers, - Andreas ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Getting my feet wet - not in Haskell though
Joachim Durchholz wrote: To adhere to uniformity, strong abstraction, and the Principle of Least Surprise, we thus chose to force lazy futures in Alice ML. Well, I wouldn't have expected that pickling has an effect (other than wrapping the value up for transfer), so at least I would have been greatly surprised. That effect is just strictness. Since you generally cannot pickle a future (and usually wouldn't want to), pickling naturally has to be strict. Making lazy futures a special case, in this one single strict operation, would be surprising (and extremely ad-hoc). - Andreas ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Aim Of Haskell
Claus Reinke wrote: but on the Pascal note: is there anything in Pascal that Haskell doesn't provide, and improves on (nested procedures, procedure parameters, distinguishing in and out parameters, types, ..)? Subrange types, maybe? But I'm sure Oleg will show us that Haskell already has them. :-) - Andreas ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell] Num is such a fat and greedy class
Lennart Augustsson wrote: let data Bar = ... in ... If you allow this you need to be very careful about type equality. When is Bar equal to Bar? If it's inside a recursive function, does each invocation get its own Bar? (In SML the answer is yes.) Can you give an example of how this would be observable in SML? AFAICS, there is no way to tell the difference, because generative type names are not allowed to escape their scope. (You can observe dynamic generativity of exception constructors, though.) If you decide the answer is no, then is the beta rule still valid? I think with the scoping restrictions in place the beta rule would not be affected. - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Num is such a fat and greedy class
S.M.Kahrs wrote: let data Bar = ... in ... If you allow this you need to be very careful about type equality. When is Bar equal to Bar? If it's inside a recursive function, does each invocation get its own Bar? (In SML the answer is yes.) Not really. In SML the answer used to be a clear no, that is: in the 1990 definition. However, that proved to be a matter of type-unsoundness, and Claudio Russo came up with an example that used this feature to break the type system. Having said this, this was based on the way the type system was defined in the language definition, the problem did not show up in implementations (which therefore failed to implement the language standard :-). The problem was fixed in the 1997 language standard. But there the answer isn't yes either, it is more like: whatever it is, you cannot tell, though technically it is still no. Mh, technically, isn't it likewise neither? As you say, types are only generated statically, and are erased in the dynamic semantics, so how is it a no more than a yes? As an aside (sorry if this is getting far too OT), in Alice ML we extend SML with dynamic types, and local types in fact *are* dynamically generative. This seemed to be the most natural semantics (and the only correct one in the presence of dynamic linking). In the static semantics, a local datatype in SML is fresh. However, this freshness is a static freshness, at compile time, and every time the code is run the same type name (a uniqueness tag for types) will be used: there is no run time type-checking, the type name is generated once, at compile time. Well, this is sort of true for types defined in functor bodies as well, still they are generative. The only semantical difference I see is that its local types are allowed to escape scope, and are (statically) renamed upon each application of the functor. No difference with respect to the dynamic semantics, however. However, that type name is not allowed to leak to the outside, i.e. not only is the identifier Bar not visible outside, the type of the value returned by the let-expression must not contain the type name associated with Bar. Thus, if a let-expression with a local datatype is evaluated twice, it does not really matter whether it uses the same or a different type name because encapsulation ensures that these type names do not interfere with each other in any way. In a nutshell: local types are not worth the trouble they cause. I'm not quite sure how this follows from your explanation. :-) Don't you just need the same standard scoping restriction as for existential types? (Which they basically are, as we know.) Why do you consider it troublesome? - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Re: GHC Error question
[EMAIL PROTECTED] wrote: I'm afraid I may disagree about the quantification. Also, I'm cautious about the phrase ML and Haskell. In GHC 6.4, local type variables behave pretty much like those in ML (actually, GHC 6.2 was closer). In GHC 6.6, the behavior is completely different! Regarding the quantification: in ML (OCaml) we can write let foo (x:'a) y = (x+1,(y:'a)) That does not mean that foo has the type forall 'a. 'a - 'a - ... Indeed, foo is not polymorphic and its inferred type is int - int - int * int. If there should be a quantifier in the above type, it probably should be 'exists' rather than 'forall'. It seems in ML, the type variables are better understood as names of some types; Be cautious about the phrase ML here as well. ;-) Because what you describe only applies to OCaml. In Standard ML, the semantics of type variables in annotations is saner: the equivalent of the above declaration would be rejected. AFAICS it is basically equivalent to the new behaviour of GHC 6.6. Cheers, - Andreas ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell-cafe] Rank N type tutorial?
Greg Buchholz [EMAIL PROTECTED] wrote: I'm not quite sure why this is illegal... foo :: Integer - (forall a. Show a = a) foo 2 = [foo] foo x = x The type signature promises that foo returns a function that has type a *for all a* (that are in Show). But neither a string list nor an integer can have all types. Rather, they are very specific. That is, what you have implemented actually could have type foo :: Integer - (exists a. Show a = a) (if GHC supported such types). Note that only bottom can have a type like forall a.a. ...while this is just fine... bar :: Integer - (forall a. Show a = a-b) - b bar 2 k = k [bar] bar x k = k x Here, you declare bar to *take* a function that delivers some b for any a. That is, the burden of defining such a function now is on the caller, not bar itself. However, in this case, defining such an argument function actually is easy, for another reason: the signature says k returns a result of type b, but b is fixed. So it is always possible to come up with a trivial instance of such a function (which will just ignore its argument). For instance, bar 2 (\_ - boo) But try to call this for a different example: ;-) baz :: Integer - (forall a b. Show a = a-b) - c baz 2 k = k [baz] baz x k = k x Hope this helps, - Andreas ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Type inference
Brian Hulley wrote: Fred Hosch wrote: Is type inferencing in Haskell essentially the same as in SML? The most significant difference certainly is that type inference has been beefed up with type classes in Haskell, which are quite a powerful mechanism refining Hindley/Milner inference. Besides that, Haskell allows some additional programs for which types can /not/ be inferred (e.g. the examples Brian was giving), while SML does not. SML also has a complicated thing called the value restriction because it allows mutable references to be altered via side effects. Because Haskell has no side effects, there is no need for a value restriction. Although there is no need for it, Haskell still has it, in minor variation. It is commonly known as The Dreaded Monomorphism Restriction ;). - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Re: [Haskell] Dynamic binding
Ralf Lammel wrote: Can you just tell how *you* would favor encoding the shapes example that was posed by poster? (It might just be that your code would be very close to Lennart's proposal?) There is no universal answer. The shape example obviously is just a toy example. As long as I have no idea what *concrete* problem the original poster is trying to solve, I cannot really tell which approach is preferable for his endeavour. It seems more appropriate to describe the options and their trade-offs. First of all, note that very often, you do not need a heterogeneous collection at all. Then plain polymorphism with type classes is more than enough, and more than OO provides in that situation. In many cases where you need some kind of heterogenicity (is that a word?), the standard datatype approach shown by Lennart is perfectly suitable - in fact, often much more suitable than the OO solution. You know about the expression problem, and the two dual notions of extensibility? OO supports one dimension, datatypes the other. It depends on the problem which one is more important. When you really need OO-style intensional kind of behaviour selection then first-class functions can bring you quite a long way, and often with much less amount of boilerplate than typical OO solutions. When the behaviour you have to encapsulate in heterogeneous collection becomes more complex - say, more then just one or two functions - first-class functions can be tedious. Existential types represent a more coarse-grained and structured variant of the first-class function approach. They combine the power of first-class functions with the convenience of type classes, very similar to class-based objects. In these cases, they are the most appropriate solution. Note again that with the latter two solutions, as with the OO approach, you do not have extensibility on the operations dimension. Cheers, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Dynamic binding
Ralf Lammel wrote: only because it's C-like :) you just can't believe that Haskell program can be 3-10 times smaller while keeping the same functionality :))) But note that same functionality is one thing, having separate compilation and program extensibility too is another one. As I said, and as is well-known, extensibility is a red herring in this context - you merely trade one dimension of extensibility for another one. Cheers, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Dynamic binding
Ralf Lammel wrote: I would like to add a peer-reviewed clear reference to the OOHaskell paper about the red herring that you mention. I don't have such a reference. May I kindly ask you to offer a few for selection? Off-hand, I recall a paper by Martin Odersky and the Scala people discussing their approach to the Expression Problem, and a related paper by Jacques Garrigue, where he proposes to solve it using OCaml's polymorphic variants. Both should be easy to dig up with Google, and probably contain further pointers. Hope this helps, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell] Dynamic binding
Andrew Ward wrote: In Simon Thompson's The Craft of Functional Programming Second Edition, page 226, it is mentioned that Laufer (1996) describes a Haskell extension to allow dynamic binding. I was wondering if this has been implemented as an extension in any of the haskell compilers, or variants? Definitely. GHC and Hugs implement it, don't know about the others. But note that you do not necessarily need it. Often a simple first-class function, or a record thereof, is enough (in fact, dynamic binding is just the OOO way of saying calling a first-class function). In typical functional programming style, you need the general thing only rarely. Cheers, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Dynamic binding
Ralf Lammel wrote: dynamic binding is just the OOO way of saying calling a first-class function). Let me presume that dynamic binding was meant here in the sense of late binding Yes. in the sense of subtyping polymorphism. No, as far as I read it, dynamic or late binding is orthogonal to subtyping, or typing in general. It is just that most typed OO languages lump these concepts together. For me, dynamic or late binding just means calling (or more generally, accessing) something that is not determined statically. That is precisely what first-class functions provide. Objects just turn more complex uses of this idiom into a language concept. Operationally, objects are equivalent to records of first-class functions. They usually come with more flexible typing and more efficient implementation, though. (First-class function seems to refer to currying or what?) No, constructing closures, and passing them around as values (currying is merely a particularly convenient special case of this). (Did you miss a polymorphic before function? That would explain it. I don't understand what you mean. Polymorphism is about typing. Late binding is not dependent on typing (there are untyped OO languages, for example). Cheers, - Andreas [Followups to Haskell Cafe] -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] translation of kind
Ralf Hinze wrote: I'ld prefer der Kind (and avoid situtations that allowed confusion with das Kind) Honestly, this is truly horrible (sorry, Peter). Just try to read it aloud: der Kind des Typkonstruktors Indeed. Moreover, my impression is that many Germans rather tend to say die Kind instead when they have to, maybe because that is the gender you have for Sorte, Art, and Gattung. -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Rank-N types vs existential types
Andre Pang wrote: data RankN = RankNEq (forall a. Eq a = a - a - Bool) | RankNOrd (forall a. Ord a = a - a - Bool) data Exists = forall a. Eq a = ExistsEq (a - a - Bool) | forall a. Ord a = ExistsOrd (a - a - Bool) So, the RankN type uses rank-2 polymorphism to hide the expression inside the type, whereas the Exists type uses existentially quantified types instead. The two seem pretty equivalent to me, since the data constructors have the same type. However, I can't help but feel that I'm missing something fundamental about a difference between them. Are the two completely isomorphic? Is there some advantage or disadvantage to using one over the other? They don't have the same type. The types are RankNEq :: (forall a.Eq a = a-a-Bool) - RankN ExistsEq :: forall a.Eq a = (a-a-Bool - Exists) These are quite different beasts. The difference really shows up when you *use* (deconstruct) them: g (RankNEq f) = (f 4 5, f True False) This allows the embedded function to be used polymorphically. But: h (ExistsEq f) = ??? Here, you cannot use f at all (well, except with undefined). The type is not polymorphic in a on the RHS, it is abstract! You'd need to encapsulate a value of the same type (or a constructing function) as well to this type useful. -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] MPTCs and type inference
Thanks for the detailed explanation that helped clearing up the smog in my head. I reckoned that once more the MR was to blame, at least for part of it. in particular, when I compare with the single parameter case: class C a where fc :: a - a - () c1 x = let p = fc x in () c2 x = let p y = fc x y in () where c1 :: C a = a - () c2 :: C a = a - () is inferred, as I would expect. The inference steps for this case are much the same except, that the inferred type for p now will be: a - (), provided that we can solve the constraint C a. Because we have assumptions about a in the environment (namely it is mentioned in the type of the varible x) we cannot generalize the type of p. It therefore remains monomorphic, and the constraint C a is propagated to the type of c2. To be more precise, p is not polymorphic *in the variables mentioned by the constraint* - the overall type of p could still be polymorphic, without changing the outcome. My understanding now is as follows: a constraint is captured by a declaration if at least one of the type variables mentioned in the constraint is generalised in the respective type scheme. Is that a correct interpretation? Of course, this is not the only possible rule. Alternatively, generalisation could always capture *all* unresolved constraints. For example, the type of p in c2 could be C a = a-() without a being quantified. That looks a bit more uniform in the face of MPTCs and would allow more programs, because contexts induced by dead code in form of an unused declaration could be forgotten consistently, not just when some of its free variables happen to be bound by a local quantifier. -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
[Haskell] MPTCs and type inference
This may well be stupidity on my side, but some experiments with multi parameter type classes got me slightly confused. Can somebody explain the following behaviour to me? class D a b where fd :: a - b - () d1 x = let p = fd x in () d2 x = let p y = fd x y in () GHC derives the following types: d1 :: D a b = a - () d2 :: a - () Hugs rejects d1 on the grounds that the type is ambiguous, but agrees on the type of d2. I do not understand where the context disappears to in this example - in particular, when I compare with the single parameter case: class C a where fc :: a - a - () c1 x = let p = fc x in () c2 x = let p y = fc x y in () where c1 :: C a = a - () c2 :: C a = a - () is inferred, as I would expect. -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell-cafe] Re: Pure Haskell Printf
Keean Schupke wrote: Remember C is typesafe In which parallel universe? -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Pure Haskell Printf
Keean Schupke wrote: I of course meant strongly-typed, you cannot pass a pointer to an int where a pointer to a float is required ... modern C compilers require you to explicitly cast. According to the C standard, void f(float *p) { *p + 1.0; } void g(void *p) { f(p); } void h(int n) { g(n); } is perfectly valid (though undefined). Where it fell down was all that automatic type promotion, and providing unsafe casts. And other things, like unions, varargs, etc. Not to speak of subtyping in C++... There is now a typesafe 'C', but I can't remember what it is called - presumably it uses some kind of linear-alias typing to make pointers safe. Do you mean Cyclone? http://www.research.att.com/projects/cyclone/ Cheers, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] mutually recursive modules
Alastair Reid wrote: Generating .hiboot files by just deleting function definitions fails if there is no prototype for an exported function. A crude approach is to assume the type (\forall a. a) for any function with no prototype but, although this is sound (I think), it will cause valid programs to be rejected. Huh? How can that ever be sound? Are you sure you didn't mean (\exists a.a)? - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] not getting most general type - is this a bug in hugs?
[EMAIL PROTECTED] wrote: rep0' :: [Integer]-- WHAT?? You just have made first contact with the Dreaded Monorphism Restriction. -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell] Per-type function namespaces (was: Data.Set whishes)
Simon Peyton-Jones wrote: If the big bug-bear is record selectors, let's focus on them exclusively. I now think that ML got it right. ML records are simply labelled tuples. Note that this is true only for SML, not for Caml. So just as (Bool,Int) is an anonymous type, so is {x::Bool, y::Int}. Indeed (Bool,Int) is just shorthand for {#1::Bool, #2::Int}. A bit of nitpicking: (Bool,Int) would be shorthand for {1::Bool,2::Int}. In SML, labels may be numeric or alpha-numeric. OTOH, the hash is the projection operator (ASCII art for \pi), which can be used for both kinds of labels: #2 (x,y,z) #b {a=x, b=y, c=z} Actually, #l is just syntactic sugar for (\{l=x,...}-x), which implies that you might need type annotations. There are no implicitly-defined record selectors either: you have to use pattern matching for that. Or projection using #. Cheers, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Per-type function namespaces (was: Data.Set whishes)
Simon Peyton-Jones wrote: | Actually, #l is just syntactic sugar for (\{l=x,...}-x), which implies | that you might need type annotations. Yes I was wrong to say that there are no implicitly-defined record selectors; (#l r) is exactly that. Syntactically I'd prefer (r.l); but regardless, it's a syntactic construct distinct from function application, which must be monomorphic. I'm not sure I parsed your sentence correctly, but in SML, (#l r) indeed *is* a function application, and #l is a perfectly normal function, as its desugared form reveals. It just fails to have a principal type (due to the lack of row polymorphism), so its type must be derivable from context - which might involve a type annotation. BTW, I'd prefer r.l as well. A section like (.l) could then give you the equivalent of #l. - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Let's get rid of those possible thingies! -- TB ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Re: Use of tab characters in indentation-sensitive code
George Russell wrote: Graham Klyne wrote (according to Wolfgang Thaller, snipped): I think that compilers should issue a warning when indentation that determines the scope of a construct is found to contain tab characters. In an ideal world, TAB characters would never have been put into ASCII, and this would be my preferred solution. However, since there would be some people who would object to such purity, a better alternative might be (a) to allow m TABs followed by n spaces at the start of lines. (b) to denote the indention of the line by the two numbers (m,n). (c) to give an error message when comparing two indentions (m1,n1),(m2,n2) where neither m1=m2,n1=n2, nor m1=m2,n1=n2. Incidentally Unicode allows far more possibilities for fun with indentation (for example half-spaces, IIRC). The most flexible but safe solution is to simply define the indentation as the sequence of indentation characters used. Two consecutive lines are indented consistently whenever one indentation is a prefix of the other. Hence you may freely mix different indentation characters, but you must be consistent across lines. Any decent editor should be able to ensure that. With this solution, tab width is irrelevant and indentation may include whatever Unicode has. - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Computer games don't affect kids; I mean if Pac Man affected us as kids, we would all be running around in darkened rooms, munching magic pills, and listening to repetitive electronic music. - Kristian Wilson, Nintendo Inc. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Gallopping Tab characters
George Russell wrote: The most flexible but safe solution is to simply define the indentation as the sequence of indentation characters used. Two consecutive lines are indented consistently whenever one indentation is a prefix of the other. Hence you may freely mix different indentation characters, but you must be consistent across lines. Any decent editor should be able to ensure that. Well no they won't, because some editors might replace blocks of 8 spaces at the start of a line with TABs (or something like that), meaning that 8 and 7 spaces would go to \t and, which your algorithm would reject. If the editor does the replacement consistently everywhere (like I would expect) then it would not change the meaning of a well-indented program. - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Computer games don't affect kids; I mean if Pac Man affected us as kids, we would all be running around in darkened rooms, munching magic pills, and listening to repetitive electronic music. - Kristian Wilson, Nintendo Inc. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Type classes and code generation
Bayley, Alistair wrote: When it's applied, the compiler will know the types of the arguments, won't it?. Which means that you would generate a version of double for each (applied) instance of Num. I don't doubt that there's a good reason this is not done: code bloat? or are there simply some expressions that can't be statically resolved? I suppose I was thinking: is the language design sufficiently clever that it's *always* possible for the compiler to infer the type instance in use, or are there some situations where it's not possible to infer the instance, so some kind of function dispatch mechanism is necessary? This almost is an FAQ. Short answer: in general it is impossible to determine statically which instances/dictionaries are needed during evaluation. Their number may even be infinite. The main reason is that Haskell allows polymorphic recursion. Consider the following (dumb) example: f :: Eq a = [a] - Bool f [] = True f (x:xs) = x == x f (map (\x - [x]) xs) The number of instances used by f depends on the length of the argument list! Determining that statically is of course undecidable. If the list is infinite, f will use infinitely many instances (potentially, depending on lazy evaluation). Another (non-Haskell-98) feature that prevents static resolution of type class dispatch are existential types, which actually provide the equivalent to real OO-style dynamic dispatch. Of course, for most practical programs, the optimization you have in mind would be possible. I doubt compilers generally do it globally, though, because it requires whole program analysis, i.e. does not interfer well with separate compilation (beside other reasons). | Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Computer games don't affect kids; I mean if Pac Man affected us as kids, we would all be running around in darkened rooms, munching magic pills, and listening to repetitive electronic music. - Kristian Wilson, Nintendo Inc. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: forall quantifier
Ketil Z. Malde wrote: I have a function declared as: anova2 :: (Fractional c, Ord b) = [a-b] - (a-c) - [a] - [Anova1 c] where the first parameter is a list of classifiers. I could simplify it, I guess, to something like classify :: Eq b = [a-b] - [a] - [[[a]]] ^^^ Isn't this one list too many? classify cs xs = ... where for each classifying function in cs, I would get the xs partitioned accordingly. E.g. classify [fst,snd] [(1,0), (1,2), (2,0)] would yield [ [(1,0), (1,2)], [(2,0)] -- classified by `fst` , [(1,0), (2,0)], [(1,2)]] -- classified by `snd` Now, obviously, the problem is that fst and snd, being passed in a list, needs to be of the same type; this complicates classifying a list of type [(Int,Bool)], for instance?. What you'd need would be an existential type of the form classify :: [exists b. Eq b = a-b] - [a] - [[a]] Such a type is not available directly in Haskell, but only through an auxilary data type: data Classifier a = forall b. Eq b = Classifier (a - b) Using that you should be able to implement classify :: [Classifier a] - [a] - [[a]] Cheers, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Computer games don't affect kids; I mean if Pac Man affected us as kids, we would all be running around in darkened rooms, munching magic pills, and listening to repetitive electronic music. - Kristian Wilson, Nintendo Inc. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: beginner's questions - fix f
Bob Koutsky wrote: remainder a b = if a b then a else remainder (a-b) b fix f = f (fix f) Rewrite remainder using fix so that it is not recursive. Function fix left me completely puzzled. With help of hugs I found out that its type is ( a - a ) - a, but I have absolutely no idea how it could be used to do anything useful. Function fix is a so-called fixpoint operator. Theory says that you can formulate any computable function using only non-recursive definitions plus fix. Can somebody provide me with an example how to use fix for something just a bit useful, if possible to rewrite remainder? Try: remainderF self a b = if a b then a else self (a-b) b remainder = fix remainderF From this example it is easy to infer how to transform arbitrary recursive definitions. Even generalising it to mutual recursion is not difficult (and left as an exercise to the reader ;-). All the best, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] Computer games don't affect kids. If Pac Man affected us as kids, we would all be running around in darkened rooms, munching pills, and listening to repetitive music. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Inferring from context declarations
Lennart Augustsson wrote: Incidentally, this has nothing to do with allowing polymorphic recursion on functions in Haskell. It could be done earlier too, but then it had to be encoded using a class and instance declaration. I would argue that methods are in fact polymorphically recursive functions. Wasn't this one motivation to allow general polymorphic recursion in Haskell - that it is in the language anyway? - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] "Computer games don't affect kids. If Pac Man affected us as kids, we would all be running around in darkened rooms, munching pills, and listening to repetitive music." ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Doing IO in foldr repeats lines?
Ian Lynagh wrote: main :: IO() main = do _ - foldl foo (return 14) ["qq\n", "ww\n", "ee\n"] putStr "" foo :: IO Int - String - IO Int foo io_l s = do l - io_l () - putStr s io_l prints (with both GHC and hugs): qq ww qq ee qq ww qq and I really don't understand why. Is the code re-evaluated every time foldl is expanded or something? Nobody seems to have answered yet, so I try to explain it. Look at your definition of foo: it actually duplicates its argument action io_l. For the first application io_l is (return 14). Let's call that io_l0. The resulting action is io_l1 = do { l - return 14; () - putStr "qq"; return 14 } which is passed at the next application. The result is io_l2 = do { l - do { l - return 14; () - putStr "qq"; return 14 } ; () - putStr "ww" ; do { l - return 14; () - putStr "qq"; return 14 } } This can be reformulated as io_l2'= do { l - return 14 ; () - putStr "qq" ; l - return 14 ; () - putStr "ww" ; l - return 14 ; () - putStr "qq" ; return 14 } And so on. Finally the complete action (io_l3) is executed by running main and produces the output you observe. Hope this helps, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] :: be declarative. be functional. just be. :: ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: class instance with nested types
Matthias Höchsmann wrote: type Sequence a = [a] data Tree a = N a (Forest a) deriving (Ord,Eq,Show) type Forest a = Sequence (Tree a) i want to construct a class Xy class Xy s a where test :: s a - a [...] instance ([] Tree) Char where test x@(N a xs):txs = a To make it syntactically correct this should at least be something like instance Xy ([] Tree) Char where test (N a xs:txs) = a But the real problem is in the expression ([] Tree), which is the same as writing [Tree]. This is not a legal type expression, since Tree is a type constructor, not a ground type, so you cannot apply it to the list constructor. What you are trying to say is probably something like this: instance Xy (\a . [Tree a]) Char -- not Haskell But unfortunately there are no lambdas on the type level - they would render the type system undecidable. For the same reason it is not allowed to use a type synonym in an instance declaration: instance Xy Forest Char -- illegal The only thing you can do is turning Forest into a data type: data Tree a = N a (Forest a) deriving (Ord,Eq,Show) data Forest a = Forest [Tree a] instance Xy Forest Char where test (Forest (N a xs:txs)) = a HTH, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] :: be declarative. be functional. just be. :: ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: class instance with nested types
I mumbled: This is not a legal type expression, since Tree is a type constructor, not a ground type, so you cannot apply it to the list constructor. The other way round, of course: you cannot apply the list constructor to it. - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] :: be declarative. be functional. just be. :: ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Compiler implementation and FP [Was: Re: Clean and Haskell]
"Frank A. Christoph" wrote: It seems to me that a compiler would be an ideal candidate for being written in an imperative language. The number of times GHC has been too slow and memory-hungry for me indicates that Haskell is not suitable for writing anything as general-purpose as a compiler. Food for thought. :) I'm in an equivocal mood tonight... [OK, I'll jump in :-)] Of course, the first sentence is an invalid generalization. It may (or may not -- I hope time will prove you wrong and Haskell code will improve performance-wise) be true that Haskell is not suitable for writing compilers. But this does not imply that FPLs in general are not suitable for writing compilers -- or even less suitable than imperative languages... It seems to be folklore in the FP community that functional languages are perfect for this task. After all, it is what they are mainly used for :-|. I wouldn't dare writing such a beast without pattern matching, higher-order functions, a powerful type system, and strong support for recursion -- things imperative languages usually lack completely. OTOH I have to admit that imperative features come in handy sometimes (eg. for unification) -- like always. Compilers like OCaml or SML/NJ are very fast, even though they have to perform quite some complex stuff. And they are `mostly functional'. (And please: not another flame war about the definition of `functional'.) - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] :: be declarative. be functional. just be. ::
Re: Units of measure
Tom Pledger wrote: Where do units of measure fit into a type system? In Haskell this should be quite easy. Off my head I would suggest something like class Unit a where unit :: Float - a value :: a - Float newtype Metres = Metres Float newtype Seconds = Seconds Float instance Unit Metres where unit = Metres value(Metres x) = x instance Unit Seconds where unit = Seconds value(Seconds x) = x newtype Prod a b = Prod Float newtype Quot a b = Quot Float instance (Unit a, Unit b) = Unit(Prod a b) where unit = Prod value(Prod x) = x instance (Unit a, Unit b) = Unit(Quot a b) where unit = Quot value(Quot x) = x infix 7 *$, /$ infix 6 +$, -$ (+$) :: (Unit a) = a - a - a (-$) :: (Unit a) = a - a - a (*$) :: (Unit a, Unit b) = a - b - Prod a b (/$) :: (Unit a, Unit b) = a - b - Quot a b x +$ y = unit(value x + value y) x -$ y = unit(value x - value y) x *$ y = Prod(value x * value y) x /$ y = Quot(value x / value y) m = Metres 5 s = Seconds 2 m' = m +$ m -- OK: Metres m2 = m *$ m -- OK: Prod Metres Metres v = m /$ s -- OK: Quot Metres Seconds a = m /$ (s *$ s) -- OK: Quot Metres (Prod Seconds Seconds) x = m -$ s -- error It would be nicer if Haskell had infix type constructors: newtype a :* b = Prod Float newtype a :/ b = Quot Float Cheers, - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] :: be declarative. be functional. just be. ::
Re: Units of measure
"D. Tweed" wrote: Isn't the issue a bit weirder than this in that you've also got pure numbers which ought be usable with the same operators (*$,etc) You are right, I overlooked that. But this is not even the most serious problem, overloading the operators accordingly might be possible with MPTCs, I think. The hard problem is that you cannot establish equalities like Prod a (Quot b a) = b Sigh. - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] :: be declarative. be functional. just be. ::
Re: The dreaded layout rule
Simon Marlow wrote: Does it mean that the following expressions would be illegal? if cond then do proc1; proc2 else do proc3; proc4 (case e of Just x - x 0; Nothing - False) Unfortunately, yes. Now one can forget about {} and use layout everywhere. He would no longer be able to forget or he would have to split some expressions into indented lines, even when they are unambiguous in one line. You could just enumerate all keywords that allow/enforce insertion of }. A suitable list for Haskell 98 might be: in where ) ] module type data newtype class instance default In fact I think that this would be the cleanest and simplest rule. (At least that is how I once implemented layout similar to Haskell's, because I couldn't get Yacc's error productions to work properly in all cases). For Haskell 2(000) I would suggest removing all but the first 4 tokens from the list above. - Andreas -- Andreas Rossberg, [EMAIL PROTECTED] :: be declarative. be functional. just be. ::
Re: Simon's H98 Notes
Frank A. Christoph wrote: Standard ML does not allow this. One important aspect of the SML module system actually is its strong separation from the core language. Not that old saw again...! Ocaml separates the two as well. Well, the new let-module feature undermines the separation quite a bit, because any expression can now contain arbitrary module code -- the module system no longer rests on top of the core language. I imagine that it could be translated into SML along these lines (excuse my rusty SML): structure M = struct ... val y = ref something ... end; structure X = struct fun f(x,y) = M.y := y; ... !M.y ... end; Or maybe not. I'm not sure of the extent of the feature, but I get the Not really. First of all, f will not be re-entrant (e.g. recursion won't work). You had to save and restore the previous value. But that's not all: consider the following (admitedly contrieved) code for example let rec f x = let module M = struct exception E end in match x with M.E - () | _ - f M.E A call like f(some_exn) will not terminate because M.E is different on each recursion. You can observe similar effects using references. The point here is that modules (and all the generative objects in it, like references, exceptions, modules, etc.) are really created at runtime, while without the let-module feature, all module instances are determined at compile time. Also, the main motivation for introducing it was to allow functor applications that depend on polymorphic type variables. I think these cannot be translated (as far as typing is concerned). (In case somebody is still interested. But this has far left the scope of the Haskell list now.) You're right, though. I meant expression-local imports, like local open M in ... \begin{nitpicking} You probably mean let open M in ... \end{nitpicking} And I agree, these are very useful sometimes (although I wouldn't call that import). - Andreas
Haskell 98 - The Underbar
Ralf Hinze wrote: * make '_' lexically a valid identifier character anywhere * but disallow identifiers starting with '_' Thus '___' would lex as '___' but then be rejected. '_' on its own remains a wild-card pattern, and illegal in expressions. ] `_' is a special case whatever option one chooses. So I can see no real ] advantage in disallowing identifiers starting with '_'. IMHO the simplest rule would be to allow '_' anywhere a lowercase letter is allowed. And "_" becomes just an ordinary keyword. Cheers, - Andreas
Re: Multi-parameter type classes
Simon L Peyton Jones wrote: GHC 3.02 supports multi-parameter type classes, but I have been guilty of not documenting precisely what that means. I've now summarised the extensions, informally but I hope precisely, at http://www.dcs.gla.ac.uk/multi-param.html That does not seem to be the correct URL. I had better luck with: http://www.dcs.gla.ac.uk/~simonpj/multi-param.html - Andreas
Re: Punning: Don't fix what ain't broken.
Tommy Thorn wrote: Koen Claessen: This brings us to another issue. Doesn't the following definition look a bit awkward? R{ x = x } Definitely wierd. The left and right-hand side denotes two different things, which AFAIK is the only place where `=' behaves like this. Wouldn't `-' have been a better choice? `-' bindings are never recursive, thus `R{ x - x } is less surprising, as the two x's can't be the same. What about using constructor syntax: R{ X x } ? Not to be taken too seriously... - Andreas