
| type Kind = Type | | What does this mean? It means that Kinds are represented by Types. Admittedly, Kinds only use a small fragment of what Types can represent, namely Arrow, and type constructor applications. So * is represented by a TyConApp with a TyCon that is called typeCon. The really annoying thing about Kinds is that there's occasionally a bit of sub-kinding. In particular error :: forall a. String -> a We want to allow error "foo" :: Int# so the kind of 'a' can't be *, nor # (the kind of unboxed types). It's an "open" kind, written "?"; both * and # are sub-kinds of ?. You should nevertheless be able to encode your kind system in the same way as GHC does. But I have been thinking that it's over-kill to use Types for Kinds, and leads to no real saving. I may well split the two types in the future. Simon

Hello,
It means that Kinds are represented by Types.
Admittedly, Kinds only use a small fragment of what Types can represent, namely Arrow, and type constructor applications. So * is represented by a TyConApp with a TyCon that is called typeCon.
The really annoying thing about Kinds is that there's occasionally a bit of sub-kinding. In particular
error :: forall a. String -> a
We want to allow error "foo" :: Int#
I have subkinding in my calculus as well, but in a completely different context. For instance, the kind of Either is + -> + -> * because Either is covariant in its arguments. But the kind of Either is also x -> x -> * (x=invariance). So we have + -> + -> * as the most specific kind of Either. Note, that the kind arrow in my system is contravariant as well. I think, that is a nice analogy to the type system. For example, let tau_1:(x -> *) -> *, tau_2:(+ -> *) -> *. Then tau_1 is usable whenever tau_2 is in operation. So from (+ -> *) <: (x -> *) it follows in my system, that (x -> *) -> * <: (+ -> *) -> *. Unfortunately I have to decide two contexts of the kind arrow. To understand this, consider my definition of kinds: Def.: Kinds are inductively defined as follows: * is a kind if kappa1 and kappa2 are kinds, then kappa1 -> kappa2 is a kind if kappa is a kind, then + -> kappa, - -> kappa, x -> kappa and alpha -> kappa alpha is a so-called kind variable, that can be instantiated by +, - or x (not by arbitrary kinds!). Further on, we have the convention, that * -> kappa has to be seen as x -> kappa. What do we mean by the term kind variable? A type tau may have the kind (alpha->beta->*)->alpha->beta->*. If one applies this type, e.g., to the arrow type constructor one gaines (tau (->)): - -> + -> *. So information about variances is propagated. This allows for subtyping in a convenient manner.
so the kind of 'a' can't be *, nor # (the kind of unboxed types). It's an "open" kind, written "?"; both * and # are sub-kinds of ?.
I have read about this issue in the sources of the GHC. I try to understand...
You should nevertheless be able to encode your kind system in the same way as GHC does.
This is a pity, because my kind system allows for a really nice type inference algorithm, that can deal with higher-kinded types properly. I hope, that I can transfer it to the GHC. I will write a short section for the commentary as soon as I completely understand the GHC kind system.
But I have been thinking that it's over-kill to use Types for Kinds, and leads to no real saving.
I think so, too, because the system from "Typing Haskell in Haskell" is very easy to understand and extend. Another advantage is, that it is closer to the Haskell report.
I may well split the two types in the future.
This would be great. Thank you for the informations, Steffen Mazanek

Hello, The GHC documentation says about // (update array operator): "For MOST array types, this operation is O(n) where n is the size of the array. However, the DiffArray type provides this operation with complexity linear in the number of updates". The word "MOST" sugggests that there are other array variants for which // is linear on the number of updates. For unboxed arrays, // is linear on the array size or number of updates ? Heron

Hi,
The GHC documentation says about // (update array operator):
"For MOST array types, this operation is O(n) where n is the size of the array. However, the DiffArray type provides this operation with complexity linear in the number of updates".
The word "MOST" sugggests that there are other array variants for which // is linear on the number of updates. For unboxed arrays, // is linear on the array size or number of updates ?
(//) is always* linear in the array size * except for DiffArrays this is because it copies the array, which takes linear time in the size of the array. In general, I think the name "array" for these data structures is a bit misleading, since nearly everyone expects an array to have constant time read and update, while these only have constant time read. - Hal

G'day all.
Quoting Hal Daume III
In general, I think the name "array" for these data structures is a bit misleading, since nearly everyone expects an array to have constant time read and update, while these only have constant time read.
It's no worse than "record" in this respect. Wouldn't everyone expect a field update to be constant time, not linear in the number of fields? Cheers, Andrew Bromage

Hi Andrew, I'd never actually thought of that, but it's somewhat less of an issue since records/data types tend to have only a small number of elements, whereas arrays tend to have a large number of elements. One thing, though, for data types (and hence records) which just occurred to me is that it seems that it really should be logarithmic in the number of fields, if the compiler/programmer needed it. For instance, one could transform:
data Foo a b c d = Foo a b c d
into
data Foo a b c d = Foo1 (Foo2 a b) (Foo2 c d) data Foo2 a b = Foo2 a b
This would make updates happen in logarithmic time, but reads would now take also log time, instead of constant time (I assume reads take constant time, though I haven't verified it). Obviously one could and should be smarter about doing this...if the program this datatype is used in tends to modify a and c simultaneously, then these should be put together. Anyway, I assume no one does this, probably because it would slow down reads...but I wonder whether one could detect that a datatype is modified frequently and, if so, transform it into this...I also wonder if it would really matter -- the constant terms would be higher, so you'd really have to have a large datatype to notice the difference, I'd imagine... - Hal -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume On Sun, 2 Nov 2003 ajb@spamcop.net wrote:
G'day all.
Quoting Hal Daume III
: In general, I think the name "array" for these data structures is a bit misleading, since nearly everyone expects an array to have constant time read and update, while these only have constant time read.
It's no worse than "record" in this respect. Wouldn't everyone expect a field update to be constant time, not linear in the number of fields?
Cheers, Andrew Bromage _______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
participants (5)
-
ajb@spamcop.net
-
Hal Daume III
-
Heron
-
Simon Peyton-Jones
-
Steffen Mazanek