Proposal: unification of style of function/data/type/class definitions
Hello haskell, we can consider functions as value-to-value mappings, 'type' definitions as type-to-type mappings, 'data' and 'class' as type-to-value mappings but their syntax are different. functions has the most convenient syntax: f patterns_for_parameters | guards = result we can improve readability of various declarations by using the same scheme: class Monad m | Functor m, Monoid m where ... instance Monad (WriterT m) | Monad m where ... data EncodedStream m h | Monad m, Stream m h = ... sequence :: [m a] -> m [a] | Monad m By moving "guards" to the right side we will get more readable definitions where most important information (type/class name and shape of parameters) are written first and less important after Even more unification can be applied to GADT-style definitions and definitions of type/data families. The following is a well-known GADT example rewritten in "functional" style: data Expr t = If (Expr Bool) (Expr t) (Expr t) Expr Int = Lit Int Expr Bool | Eq t = Eq (Expr t) (Expr t) And next is the example of type function which selects optimal array representation depending on type of its elements: type Arr Bool = BitVector Arr u | Unboxed u = UArray u Arr (a,b) = (Arr a, Arr b) Arr a = Array a where Unboxed is a class whose instances are unboxable types. We can also allow to use as guards partial type functions, i.e. functions that defined only for subset of type parameters: type SeqElem [a] = a SeqElem (Sequence a) = a SeqElem (Array a) = a data Collection c | SeqElem c = Coll c In general, any type-level computation can use: * in patterns - any type constructors declared in 'data' statements and their saturated synonyms * in guards - classes (and partial type functions) * at the right side - any type constructors and type functions declared with data/type statements, including associated types/type synonyms Please note that ordinal functions dispatch (via pattern-matching) on the data constructors which appear at the right side of 'data' definitions while type-level computations dispatch (again via pattern-matching) on type constructors which appears on left side of the same 'data' definitions ps: although this idea seems more appropriate for haskell' committee, i propose to use it just now, starting from implementation of different syntax for GADTs -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com
Hi,
class Monad m | Functor m, Monoid m where ...
Nice - I was having exactly this problem in Hoogle, if you list all the class dependancies first, you can't really see the actual class. It also makes grep'ing easier.
data EncodedStream m h | Monad m, Stream m h = ...
Ditto
sequence :: [m a] -> m [a] | Monad m
I don't like this. In the other two instances you are moving the most important information (the name of the thing) to the front. In this the name is at the front, but the instances move to the end, which isn't really where they should be. And following the function | rule function | predicates = body I would have said that logically, you want: sequence | Monad m :: [m a] -> m [a] (of course, this might present a problem for parsing...) Note this also makes sense compared to your: data Data | Classes = Alternatives design as well Thanks Neil
"Neil Mitchell" <ndmitchell@gmail.com> writes:
Hi,
class Monad m | Functor m, Monoid m where ...
Nice - I was having exactly this problem in Hoogle, if you list all the class dependancies first, you can't really see the actual class. It also makes grep'ing easier.
data EncodedStream m h | Monad m, Stream m h = ...
Ditto
sequence :: [m a] -> m [a] | Monad m
I don't like this. In the other two instances you are moving the most important information (the name of the thing) to the front. In this the name is at the front, but the instances move to the end, which isn't really where they should be.
I don't see the problem. You can read all of Bulat's examples as "'thing being declared' 'relationship' 'value' given that 'context'", so this one is "“sequence” has type “[m a] -> m [a]” given that “m” is a “Monad”". So viewed that way, they're all consistent with each other. [Hmm. I think I need to restrain myself a bit on the use of different types of quotation mark :-)] Isn't the etiquette to discuss postings here in the café? -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk
On Sun, Sep 10, 2006 at 10:08:22AM +0400, Bulat Ziganshin wrote:
we can improve readability of various declarations by using the same scheme:
class Monad m | Functor m, Monoid m where ...
instance Monad (WriterT m) | Monad m where ...
sequence :: [m a] -> m [a] | Monad m
I am not entirely sure, but I think this syntax for type class context is used in the Concurrent Clean language. Best regards Tomasz
On 9/10/06, Bulat Ziganshin <bulat.ziganshin@gmail.com> wrote:
data Expr t = If (Expr Bool) (Expr t) (Expr t) Expr Int = Lit Int Expr Bool | Eq t = Eq (Expr t) (Expr t)
I find this somewhat unreadable due to the implicit "t" parameter not showing up on the left-hand side... -- Taral <taralx@gmail.com> "You can't prove anything." -- Gödel's Incompetence Theorem
participants (5)
-
Bulat Ziganshin -
Jón Fairbairn -
Neil Mitchell -
Taral -
Tomasz Zielonka