How to print the name of a variable

I have a number of variables (whose values are computed in my program) of the same type, and in ghci I want to be able to call a function to print something computed from the value of one or more of these to a file. I want the file name to reflect the name of the variable. This is probably not clear, but conceptually the function to do the output would look something like this: someFunction :: MyTypeVariable -> String writeFileFor :: MyTypeVariable -> IO () writeFileFor v = do nameOfV <- someFunction v outh <- openFile nameOfV ++ ".txt" WriteMode outputstring = calculationsFrom v hPutStr outh outputstring hClose outh Is there any such "someFunction", or is there a way to build one? Thanks, John Velman

Hi John I can't see there is a way of getting the name of a variable. A Haskell compiler like GHC is fairly free to do what it likes with /values/, so a variable doesn't necessarily exist in a tangible form in a program - i.e. it might get compiled away due to constant folding[*]: main = let x = 5 in do { print (10 * x) } ... would likely become: main = do { print (10 * 5) } -- by constant folding ... and finally main = do { print 50 } -- by static expression elimination -- Values not /variables/ - are more tangible. Provided the type of the value is an instance of the type class Data, you can get at least the value's type name and its constructor name. To get something like named variable you would have to make a data type with two fields one for a name label and one for the value, e.g. : data Named a = Named String a deriving (Show) valName :: Named a -> String valName (Name s _) = s valValue :: Named a -> a valValue (Name _ a) = a When you use a variable you want associated with a name, you will have to be a bit pedantic about always supplying the same name to construct it: e.g.: if you have a constant called scale_factor scale_factor :: Named Int scale_factor = Named "scale_factor" 10 [At an advanced level you could probably use Template Haskell to make this easier] -- Your program would then be something like : writeFileFor :: Named a -> IO () writeFileFor v = do let nameOfV = valName v outh <- openFile (nameOfV ++ ".txt") WriteMode let outputstring = calculationsFrom (varValue v) hPutStr outh outputstring hClose outh Though it would more succinct to use pattern matching: writeFileFor :: Named a -> IO () writeFileFor (Named name value) = do outh <- openFile (name ++ ".txt") WriteMode let outputstring = calculationsFrom value hPutStr outh outputstring hClose outh As a side issue - having access to variables rather than values seems an usually prospect for any programming language. I'd guess that it would effectively prevent the language being compiled or the language would would have to limit reflective / introspective access only to global variables. Best wishes Stephen [*] Actually for important reasons GHC does not do that much constant folding - but it is possibly the easiest optimization to use as an illustration here.

This is what I have in my library. I use it every now and then, when I need
sth with a name. Of course you still have to implement the name function for
that data type, but I've no better way of doing it.
class Show a => HasName a where
-- | accessor method for name
name :: a -> String
-- | a method the update the stored name
updateName :: String -> a -> a
-- | show functions (for this type-class) are assumed to be shown
*without* the name
-- | if you want to show with the name, you must use this function
instead of show
-- | default implementation should be almost always sufficient.
showWithName :: a -> String
-- | prints instead of just showing.
-- | default implementation should be almost always sufficient.
printWithName :: a -> IO()
-- | if "name" is not implemented, just return a notice
name x = "don't know my name: " ++ show x
-- | if "updateName" is not implemented, there is nothing to do but
giving an error
updateName n x = error ("updateName(" ++ n ++ ") not implemented: " ++
show x)
showWithName p = name p ++ ": " ++ show p
printWithName = putStrLn . showWithName
Hope it helps,
On 20 March 2010 10:09, Stephen Tetley
Hi John
I can't see there is a way of getting the name of a variable.
A Haskell compiler like GHC is fairly free to do what it likes with /values/, so a variable doesn't necessarily exist in a tangible form in a program - i.e. it might get compiled away due to constant folding[*]:
main = let x = 5 in do { print (10 * x) }
... would likely become:
main = do { print (10 * 5) } -- by constant folding
... and finally
main = do { print 50 } -- by static expression elimination
--
Values not /variables/ - are more tangible. Provided the type of the value is an instance of the type class Data, you can get at least the value's type name and its constructor name.
To get something like named variable you would have to make a data type with two fields one for a name label and one for the value, e.g. :
data Named a = Named String a deriving (Show)
valName :: Named a -> String valName (Name s _) = s
valValue :: Named a -> a valValue (Name _ a) = a
When you use a variable you want associated with a name, you will have to be a bit pedantic about always supplying the same name to construct it:
e.g.: if you have a constant called scale_factor
scale_factor :: Named Int scale_factor = Named "scale_factor" 10
[At an advanced level you could probably use Template Haskell to make this easier]
--
Your program would then be something like :
writeFileFor :: Named a -> IO () writeFileFor v = do let nameOfV = valName v outh <- openFile (nameOfV ++ ".txt") WriteMode
let outputstring = calculationsFrom (varValue v)
hPutStr outh outputstring
hClose outh
Though it would more succinct to use pattern matching:
writeFileFor :: Named a -> IO () writeFileFor (Named name value) = do outh <- openFile (name ++ ".txt") WriteMode
let outputstring = calculationsFrom value
hPutStr outh outputstring
hClose outh
As a side issue - having access to variables rather than values seems an usually prospect for any programming language. I'd guess that it would effectively prevent the language being compiled or the language would would have to limit reflective / introspective access only to global variables.
Best wishes
Stephen
[*] Actually for important reasons GHC does not do that much constant folding - but it is possibly the easiest optimization to use as an illustration here. _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
-- Ozgur Akgun

Hi Ozgur Doesn't that associate names with types rather than names with values though: instance HasName Int where name = "Int"
printWithName (1::Int) Int: 1
printWithName (70::Int) Int: 70
I think the same is achievable with Data.Typeable / Data.Data although how to do it is somewhat buried... For associating names and values you'd still need to do it 'by hand' with something like data Named a = Named String a deriving (Show) or type Named a = (String,a) Best wishes Stephen

You're right, if you implement the type class independent of the value
you'll end up with associating names with types.
I use it as an interface to your method actually - sorry I didn't make it
clear enough.
So, something like this:
data NamedInt = NamedInt Int String
instance HasName NamedInt where
name (NamedInt _ n) = n
updateName n (NamedInt v _) = NamedInt v n
Now, if you want, you can have a Num instance for Named Int, redirect
everything to the inner-int, and here you go. You can use NamedInt as a Num
seamlessly.
Cheers,
On 20 March 2010 11:03, Stephen Tetley
Hi Ozgur
Doesn't that associate names with types rather than names with values though:
instance HasName Int where name = "Int"
printWithName (1::Int) Int: 1
printWithName (70::Int) Int: 70
I think the same is achievable with Data.Typeable / Data.Data although how to do it is somewhat buried...
For associating names and values you'd still need to do it 'by hand' with something like
data Named a = Named String a deriving (Show)
or
type Named a = (String,a)
Best wishes
Stephen _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
-- Ozgur Akgun

Hi Ozgur Thanks for the qualification - I can see the benefit now. Best wishes Stephen

Thanks, Stephen and Ozgur. Your responses were helpful and educational. Best, John V. On Sat, Mar 20, 2010 at 02:05:30PM +0000, Stephen Tetley wrote:
Hi Ozgur
Thanks for the qualification - I can see the benefit now.
Best wishes
Stephen _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
participants (3)
-
John Velman
-
Ozgur Akgun
-
Stephen Tetley