My tuppence:
I feel like the main impetus for TDNR is the awkwardness of records, especially
when there are multiple record types within a module (as there often are). Now,
if one proceeds as one has to today, then one may find:
data Foo = Foo { fooName :: String, fooValue :: Double }
data Bar = Bar { barName :: String, barValue :: [String], barSubbars :: [Bar] }
Let us, for sake of argument, ignore that perhaps fooName and barName represent
the same semantic concept and these should all somehow be refactored.
I suspect that the prime annoyance, the thing that makes us yearn for our old
C/C++/Java/Python ways, is the tediousness of having to prefix all the field
names with "foo" or "bar". Especially when the data type name is large, one
ends up having to invent coding conventions one doesn't want to:
data ExecutionTraceSummary = ExecutionTraceSummary { etsStart :: Time; ... }
So imagine that we take the tedium out of typing all those prefixes by
anointing some initial character, say the apostrophe, as a sort of name mangler:
data Foo = Foo { 'name :: String, 'value :: Double }
data Bar = Bar { 'name :: String, 'value :: [String], 'subbars :: [bar] }
data ExecutionTraceSummary = ExecutionTraceSummary { 'start :: Time, ... }
Now, to use them, perhaps we have to explicitly write the full form:
showFoo :: Foo -> String
showFoo f = Foo'name f ++ "(" ++ show (Foo'value f) ++ ")"
We could allow a form of shortened local reference by allowing the full form to
"flow through" type declarations:
type ETS = ExecutionTraceSummary
logExecutionTraceSummary :: ExecutionTraceSummary -> IO ()
logExecutionTraceSummary s = do
putStr $ ETS'start s
Mind you, I realize that apostrophe may not work here, and details haven't been
worked out.
[...that was the first pence, here comes the second...]
If you buy any of that, then one could allow, in the manner pointed out by some
(though in particular I'm thinking of David Menendez's example), that this
construction could imply a type class and associated type. That is, the first
appearance of 'name in a record implies this:
class <C>'name a where
type <R>'name a :: *
'name :: a -> <R>'name a
and for each appearance of 'name :: X as a field of Foo:
instance <C>'name Foo where
type <R>'name Foo = X
'name = Foo'name
(Here, <C> and <R> are some unwritable prefixes used by the compiler. It
remains to be seen if these should be module scoped or program global.)
So, in the case (repeated from above):
data Foo = Foo { 'name :: String, 'value :: Double }
data Bar = Bar { 'name :: String, 'value :: [String], 'subbars :: [Bar] }
We get auto generated:
class <C>'name a where
type <R>'name a :: *
'name :: a -> <R>'name a
class <C>'value a where
type <R>'value a :: *
'value :: a -> <R>'value a
class <C>'subbars a where
type <R>'subbars a :: *
'subbars :: a -> <R>'subbars a
instance <C>'name Foo where
type <R>'name Foo = String
'name = Foo'name
instance <C>'name Bar where
type <R>'name Bar = String
'name = Bar'name
instance <C>'value Foo where
type <R>'value Foo = Double
'value = Foo'value
instance <C>'value Bar where
type <R>'value Bar = [String]
'value = Bar'value
instance <C>'subbars Bar where
type <R>'subbars Bar = [Bar]
'subbars = Bar'subbars
*Now* one can write:
showFoo :: Foo -> String
showFoo f = 'name f ++ "(" ++ show ('value f) ++ ")"
nameBoth :: Foo -> Bar -> String
nameBoth f b = 'name f ++ " " ++ 'name b
None of this requires any more type machinery than already exists with
TypeFamilies. It perhaps suffer some of the prior objections to implying
semantic equivalence (in say the 'value fields) where none exists. But, it is
limited in scope to fields, and only when one uses the special naming sigil
(apostrophe here).
Of course, this approach would meld nicely with any better record/label system.
For starters:
class <C>'name a where
type <R>'name a :: *
'name :: a -> <R>'name a
''name :: <R>'name a -> a -> a
instance <C>'name Foo where
type <R>'name Foo = String
'name = Foo'name
''name = \v x -> x { Foo'name = v }
There now -- I feel like TNDR is placating the muscle memory in our fingers
that wants to type "f.name" ... and I hope we find a solution to replacing the
tedium of so many "fooName" fields, and perhaps solve the record update
ugliness as well!
- Mark
Mark Lentczner
http://www.ozonehouse.com/mark/
IRC: mtnviewmark
_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe