[Haskell-cafe] Useful IDE features - "implement instance"
Claus Reinke
claus.reinke at talk21.com
Tue Jun 19 07:37:19 EDT 2007
> 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
More information about the Haskell-Cafe
mailing list