
That looks nice, just unfortunate you need to cast to ::Float in homer2?Age::Float. I don't see why this is needed, but I must say I don't understand your code completely yet, working on that :) Also, wouldn't this approach be less performant? Or is GHC that good that ist compiles away all the overhead?
----- Oorspronkelijk bericht ----- Van: Claus Reinke [mailto:claus.reinke@talk21.com] Verzonden: dinsdag, juni 19, 2007 01:37 PM Aan: haskell-cafe@haskell.org Onderwerp: Re: [Haskell-cafe] Useful IDE features - "implement instance"
Just another wild idea which I might find useful, but is more like refactoring, is to convert the fields of a record to get/set type-classes, and refactor all usages of those fields.
you could use a preprocessor (DrIFT, Data.Derive) to derive the instances, but you need to share the class declarations between all client modules.
------------------- data Person = Person { name :: String, age :: Float }
main = print $ name p ++ " is " ++ show (age p) ++ " years old" where p = Person { name = "Homer", age = 41 } ------------------- ..
alternatively, you could generalise this a bit, so that there is only one class for all combinations of records, fields, and field value types, and then generalise it further so that you only need one pair of instances to define selection and update for all records. that kind of operates at the borders of the language, so you lose portability (the nicest version is ghc-only; nearly all language extensions used are also supported by hugs, but with a slightly different interpretation). you'd still need to share the label types between all client modules.
claus
---------------------------------------------------------- {-# OPTIONS_GHC -fallow-undecidable-instances #-} {-# OPTIONS_GHC -fallow-overlapping-instances #-} {-# OPTIONS_GHC -fglasgow-exts #-}
infixl ? infixr <:,:<
------------------- poor man's records
-- record extension -- (ghc only: infix constructor; for hugs, use (,) instead) data fieldValue :< record = fieldValue :< record
-- field selection (?) and update (<:) -- needs overlapping instances to recurse down record extensions -- for hugs: drop the functional dependency, use more type annotations class Has field value record | field record -> value where (?) :: record -> field -> value (<:) :: (field,value) -> record -> record
-- if the first field matches, we're done instance Has field value ((field,value) :< record) where ((_f,v) :< _) ? f = v (f,v) <: ((_f,_) :< r) = ((f,v) :< r)
-- otherwise, try again, with the remaining record instance Has field value record => Has field value ((f,v) :< record) where ((f',v') :< r) ? f = r ? f (f,v) <: ((f',v') :< r) = ((f',v') :< ( (f,v)<:r ) )
-- some field labels data Name = Name data Age = Age
------------------- a generic version, no separate Person type or instances
type Person1 = (Name,String) :< (Age,Float) :< ()
homer :: Person1 homer = (Name,"Homer") :< (Age,41) :< ()
test1 = print $ homer?Name ++ " is " ++ show(homer?Age) ++ " years old"
------------------- a more down-to-earth version, closer to the original
data Person = Person String Float
instance Has Name String Person where (Person name age) ? Name = name (Name,newName) <: (Person name age) = Person newName age
instance Has Age Float Person where (Person name age) ? Age = age (Age,newAge) <: (Person name age) = Person name newAge
defaultPerson = Person "" 0
homer2 = (Name,"Homer2") <: (Age,42::Float) <: defaultPerson
test2 = print $ homer2?Name ++ " is " ++ show(homer2?Age::Float) ++ " years old"
-------------------
main = test1 >> test2
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

That looks nice, just unfortunate you need to cast to ::Float in homer2?Age::Float. I don't see why this is needed, but I must say I don't understand your code completely yet, working on that :)
that annotation is not needed if you keep the functional dependency (which just states that record type and field label type together uniquely determine the field value type)
class Has field value record | field record -> value where (?) :: record -> field -> value (<:) :: (field,value) -> record -> record
Also, wouldn't this approach be less performant? Or is GHC that good that ist compiles away all the overhead?
in principle, there is no need for this to be less performant. in practice, overloading introduces overhead that might hamper performance. claus

(which just states that record type and field label type together uniquely determine the field value type)
in practice, overloading introduces overhead that might hamper
That's nice. When will a new Haskell standard become official? It seems so many new extensions exist, that one cannot judge the language by looking at "Haskell98" anymore. performance. You mean overloading in general, so using type classes? Is this comparable to the Java/C#/C++ overhead with virtual methods, so one extra level of indirection before the function gets called? Or is it much worse? -----Original Message----- From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Claus Reinke Sent: Wednesday, June 20, 2007 01:28 To: haskell-cafe@haskell.org Subject: Re: [Haskell-cafe] Useful IDE features -
That looks nice, just unfortunate you need to cast to ::Float in homer2?Age::Float. I don't see why this is needed, but I must say I don't understand your code completely yet, working on that :)
that annotation is not needed if you keep the functional dependency (which just states that record type and field label type together uniquely determine the field value type)
class Has field value record | field record -> value where (?) :: record -> field -> value (<:) :: (field,value) -> record -> record
Also, wouldn't this approach be less performant? Or is GHC that good that ist compiles away all the overhead?
in principle, there is no need for this to be less performant. in practice, overloading introduces overhead that might hamper performance. claus _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe No virus found in this incoming message. Checked by AVG Free Edition. Version: 7.5.472 / Virus Database: 269.9.1/854 - Release Date: 19/06/2007 13:12 No virus found in this outgoing message. Checked by AVG Free Edition. Version: 7.5.472 / Virus Database: 269.9.1/854 - Release Date: 19/06/2007 13:12

peterv writes:
That's nice. When will a new Haskell standard become official? It seems so many new extensions exist, that one cannot judge the language by looking at "Haskell98" anymore.
When haskell-prime is ready, which won't be before the MPTC Dilemma [1] gets resolved, which probably won't be until associated types get fully implemented in GHC, a new version of GHC gets released and people start to use them. [1]: http://hackage.haskell.org/trac/haskell-prime/wiki/MultiParamTypeClassesDile... -- -David House, dmhouse@gmail.com

in practice, overloading introduces overhead that might hamper performance.
You mean overloading in general, so using type classes? Is this comparable to the Java/C#/C++ overhead with virtual methods, so one extra level of indirection before the function gets called? Or is it much worse?
usually, don't worry about it. if a program really is slow, still don't worry about it, but find out where that program is slow. only if a program is slow in an area that uses overloading, see: http://www.haskell.org/haskellwiki/Performance/Overloading and even there, the advice is not to avoid overloading, but to make sure that you use specialised versions of overloaded code (by giving more specific type annotations or specialize pragmas, or by inlining overloaded code into usage contexts where its overloading can be resolved to specific types). claus

On Thu, 2007-06-21 at 00:20 +0100, Claus Reinke wrote:
in practice, overloading introduces overhead that might hamper performance.
You mean overloading in general, so using type classes? Is this comparable to the Java/C#/C++ overhead with virtual methods, so one extra level of indirection before the function gets called? Or is it much worse?
usually, don't worry about it. if a program really is slow, still don't worry about it, but find out where that program is slow. only if a program is slow in an area that uses overloading, see:
Is this something that could be caught by profiling? Could profiling somehow notice what specific type a polymorphic function is called with, and more or less explicitly suggest which functions to specialize? (I guess I'll soon be asking for profile directed optimization :-) -k
participants (5)
-
Claus Reinke
-
David House
-
Ketil Malde
-
Peter Verswyvelen
-
peterv