Function to output function name
Asked Answered
W

5

11

Is it possible in Haskell to implement a function which returns its own function name?

A possible type could be (a -> b) -> String.

Wilks answered 7/3, 2013 at 13:16 Comment(6)
No. A function of type (a -> b) -> String can't inspect its argument (beyond seqing it or applying it to bottom) due to its polymorphic type. Thus it has no means to identify its argument.Hibachi
If a function returns its own function name, wouldn't the type be () -> String (and the implementation rather trivial)?Bittner
Most functions in Haskell don't even have names. Something that could exist would be a function that shows the type of an expression, although I doubt that would be very useful.Message
If you had a function like that, what would you use it for? There's probably a simpler solution to your problem.Illegal
In addition to what Daniel Fischer said, this would violate equational reasoning: let f = id in findName f would presumably be intended to produce "f", but findName id would presumably be intended to produce "id". This is all related to the fact that functions simply don't have names; variables can be in scope which have function type, but that's it.Saintsimonianism
I found this question because I was looking for a way to trace the execution of certain functions without having to change each function. Not sure what the Haskelly way to do that is but I was looking for some equivalent to the way log4j uses reflection to give class execution context when logging.Mame
U
19

You want a function that takes a function argument, and returns the definition site variable name that corresponds to the name of that function?

This isn't possibly without meta-programming, which is usually a sign you're doing something wrong :). But assuming you're not, one way to achieve something in the right direction is via Template Haskell, which can get at unique names (how the compiler names things). E.g.

Prelude Language.Haskell.TH> :set -XTemplateHaskell
Prelude Language.Haskell.TH> let f x y = x + y
Prelude Language.Haskell.TH> $( stringE . show =<< reify 'f )

     "VarI f_1627394057
                (ForallT [PlainTV a_1627394063]
                         [ClassP GHC.Num.Num [VarT a_1627394063]]
                              (AppT (AppT ArrowT (VarT a_1627394063)) 
                                    (AppT (AppT ArrowT (VarT a_1627394063)) 
                                         (VarT a_1627394063)))) 
                         Nothing (Fixity 9 InfixL)"

And now we know a lot about the variable. So you can play games by passing a Name to the function (via 'f) rather than f itself.

You are certainly in the world of reflection and meta-programming though, so it would help to know more about what you are trying to do.

Usable answered 7/3, 2013 at 14:40 Comment(0)
S
6

To clarify something mentioned in dons' post: no functions have names in Haskell. There are bindings which may bind functions, but if I had such a function (call it getName) as you seek then what would you expect this to return:

let f x = x
    g   = f
    h   = f
in  getName g == getName h
Spoil answered 7/3, 2013 at 16:46 Comment(0)
J
1

I don't know what you need it for, but maybe a simplistic solution suffices? Like so:

data NamedFunction a b = NamedFunction { 
    name :: String,
    apply :: a -> b
}

timesTwo :: NamedFunction Int Int
timesTwo = NamedFunction "timesTwo" (\x -> 2 * x)

which you can use as follows:

ghci> timesTwo `apply` 7
14
ghci> name timesTwo
"timesTwo"

You can then write your own version of (.):

-- contrast (.)  ::    (b -> c) ->          (a -> b) ->         (a -> c)
compose :: NamedFunction b c -> NamedFunction a b -> NamedFunction a c
compose (NamedFunction n1 f1) (NamedFunction n2 f2) = 
     NamedFunction (n1++ " . " ++ n2) (f1 . f2)

In ghci:

ghci> let f = timesTwo `compose` timesTwo in (f `apply` 7, name f) 
(28,"timesTwo . timesTwo")

You'll have to reimplement your own versions of map, filter and so on, and you're bound to run into other problems later, but maybe this is all you need...

Jugular answered 7/3, 2013 at 17:11 Comment(0)
M
0

Am I missing something? This function returns its own function name.

Prelude> let myNameIs::(a->b) -> String; myNameIs f = "myNameIs"
Prelude> :type myNameIs
myNameIs :: (a -> b) -> String
Prelude> myNameIs myNameIs
"myNameIs"
Marr answered 7/3, 2013 at 14:42 Comment(0)
B
0

You can preprocess your source code with CPP. In CPP

#define _NAMEOF(name) #name

defines a macro, _NAMEOF, for stringifying text (including surrounding it with programmer's quotation marks). You can then use it as follows:

head [] = error $ _NAMEOF(head) ++ ": empty list!"

which CPP should translate into a valid Haskell source code line:

head [] = error $ "head" ++ ": empty list!"
Boil answered 2/11, 2020 at 21:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.