在Haskell中是否可以实现一个返回其自己的函数名的函数?
可能的类型可能是(a -> b) -> String
。
答案 0 :(得分:15)
你想要一个带有函数参数的函数,并返回与该函数名称对应的定义站点变量名吗?
这可能不是没有元编程,这通常表明你做错了:)。 但假设你不是,那么通过Template Haskell获得正确方向的一种方法就是获得独特的名称(编译器如何命名)。 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)"
现在我们对这个变量了解很多。因此,您可以通过将名称传递给函数(通过'f)而不是f本身来玩游戏。
你当然处于反思和元编程的世界,所以它有助于更多地了解你想要做的事情。
答案 1 :(得分:5)
澄清dons'帖子中提到的内容:没有函数在Haskell中有名字。有绑定可以绑定函数,但如果我在你寻求的时候有这样的函数(称之为getName
)那么你期望它返回什么:
let f x = x
g = f
h = f
in getName g == getName h
答案 2 :(得分:1)
我错过了什么吗?此函数返回其自己的函数名称。
Prelude> let myNameIs::(a->b) -> String; myNameIs f = "myNameIs"
Prelude> :type myNameIs
myNameIs :: (a -> b) -> String
Prelude> myNameIs myNameIs
"myNameIs"
答案 3 :(得分:1)
我不知道你需要它,但也许一个简单的解决方案就足够了?像这样:
data NamedFunction a b = NamedFunction {
name :: String,
apply :: a -> b
}
timesTwo :: NamedFunction Int Int
timesTwo = NamedFunction "timesTwo" (\x -> 2 * x)
您可以使用如下:
ghci> timesTwo `apply` 7
14
ghci> name timesTwo
"timesTwo"
然后您可以编写自己的(.)
版本:
-- 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)
在ghci:
ghci> let f = timesTwo `compose` timesTwo in (f `apply` 7, name f)
(28,"timesTwo . timesTwo")
你必须重新实现自己版本的map
,filter
等等,以后你一定会遇到其他问题,但也许这就是你需要的......
答案 4 :(得分:0)
您可以使用CPP预处理源代码。在CPP中
#define _NAMEOF(name) #name
定义一个宏_NAMEOF
,用于对文本进行字符串化(包括用程序员的引号引起来)。然后,您可以按以下方式使用它:
head [] = error $ _NAMEOF(head) ++ ": empty list!"
哪个CPP应该转换为有效的Haskell源代码行:
head [] = error $ "head" ++ ": empty list!"