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
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to