On Sun, 2007-09-16 at 19:00 -0700, Erick Tryzelaar wrote: > I put this up on trac in case anyone is interested.
> > I'm sure it'd be a lot of effort to pull this off, but it'd be interesting > > if we could extend this to data structures so we could implement: > > > > {{{ > > union hlist[T with Show[T]] = > > | HEmpty > > | HCons of T * hlist[T] > > ; > > }}} Not sure I understand: ///////////////////////////// #import <flx.flxh> union hlist[T with Show[T]] = | HEmpty | HCons of T * hlist[T] ; var x= HEmpty[int]; println$ caseno x; //////////////////////////// [EMAIL PROTECTED]:/work/felix/svn/felix/felix/trunk$ f ex 0 //////////////// you should note there is a 'bug' in typeclasses. Typeclasses are ignored. Typeclasses are just like C++ class templates specialisations (in Haskell too). In Felix, the there is no typechecking at all. What this means is that if you instantiate something using say Show[T] = Repr[T] + Str[T] and you only use the str part of it .. it will work, even if the type doesn't support Repr. All the checking is done on use. This is the same as C++ class template method specialisations. This is not really what should happen.. there are routines to do instance checking at binding time, but they're horribly messy and don't work anyhow. Messy because they have to deal with unbound symbols. Don't work because there's no way to locate an instance without global analysis. Although transfer of constraint as in: fun f[T with X[T]] (x:T) => g x; fun g[T with X[T] .. CAN be checked after binding, that is, the call g x here could be checked, as in Haskell, this is not enough. If you 'open' a typeclass, say X[int], then a call g 1 cannot be checked just against the calling function's encapsulated typeclass .. you have to check against the opened typeclasses too. This is the same as nested functions: the parent typeclasses are available to children. THAT IS: typeclasses come from two places, the current function type parameters AND the enclosing context. The enclosing context can contain instances, parameters usually only have constraints. The thing is: to check g 1 ignoring instances, the result is 'alway true' provided X typeclass is defined at all .. and it must be or g couldn't be compiled. This is true even inside a function. EG even if the constraint X[T] inside f is not enough to ensure g (x,x) works .. it doesn't need to be .. the call is still valid if the 'instance' open[T] X[T] is specified. This is so hard to check. EG if you write: typeclass X[T] .. instance X[int] fun g[T with X[T] .. g 1; what happens? Is the call disallowed because the constraint wasn't propagated? Or do we take the instance as satisfying it? If the latter .. well, it isn't possible to FIND all the instances at type checking time, except by exhaustive searching. Felix doesn't bother any more. It just checks individual methods are instantiable. It only bugs out if you call a virtual which is not instantiated. It fails to bug out if you do that but one of the other required virtuals isn't instantiated.. if you don't call it, no error. This is not right, but it Felix isn't Haskell .. it's a global analyser and it handles this the same way as C++: at global analysis time (link time in C++) all methods have to be instantiated. Note that type checking *recursive* instantiation is a real problem.. there's no problem instantiating them though. There are two types of recursion: polymorphic recursion (not really recursion!) and real recursion. If you're Showing a list with Str, and you use a recursion which applies Str on the tail after displaying the head then: * the head display is merely polymorphic recursion * the tail display is a real recursion Note polymorphic recursion where the types agree is real recursion. Polymorphic recursion is a bitch because it can diverge.. we have a test where that happens. Felix doesn't have second order unification so it can't detect this. Eg str (x:T)=>str (x,x) creates an infinite set of instances of str for t = int int * int (int * int) * (int * int) etc. The type diverges. Note, the *function* calls aren't not recursive, its just that there is an infinite set of functions which call each other in a chain. What diverges .. is the Felix compiler. There's no easy way to detect this because the polymorphic recursion doesn't have to be self, there could be two mutually polymorphically recursive functions. [BTW: Haskell does do second order unification and it does detect this and bug out] -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language