10

是否可以在 Haskell 中实现一个返回自己的函数名的函数?

一种可能的类型可能是(a -> b) -> String.

4

5 回答 5

17

您想要一个接受函数参数并返回与该函数名称相对应的定义站点变量名称的函数吗?

这不可能没有元编程,这通常表明你做错了:)。但假设你不是,实现正确方向的一种方法是通过Template Haskell,它可以获得唯一的名称(编译器如何命名事物)。例如

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 本身来玩游戏。

不过,您肯定处于反射和元编程的世界中,因此更多地了解您正在尝试做什么会有所帮助。

于 2013-03-07T14:40:18.423 回答
6

为了澄清 dons 的帖子中提到的内容:Haskell 中没有函数有名称。有一些绑定可以绑定函数,但是如果我有这样一个函数(调用它getName),那么你期望它返回什么:

let f x = x
    g   = f
    h   = f
in  getName g == getName h
于 2013-03-07T16:46:28.240 回答
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")

你必须重新实现你自己的版本mapfilter等等,你以后肯定会遇到其他问题,但也许这就是你所需要的......

于 2013-03-07T17:11:40.507 回答
0

我错过了什么吗?这个函数返回它自己的函数名。

Prelude> let myNameIs::(a->b) -> String; myNameIs f = "myNameIs"
Prelude> :type myNameIs
myNameIs :: (a -> b) -> String
Prelude> myNameIs myNameIs
"myNameIs"
于 2013-03-07T14:42:38.197 回答
0

您可以使用 CPP 预处理您的源代码。在 CPP 中

#define _NAMEOF(name) #name

定义一个宏 ,_NAMEOF用于字符串化文本(包括用程序员的引号括起来)。然后,您可以按如下方式使用它:

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

哪个 CPP 应该转换为有效的 Haskell 源代码行:

head [] = error $ "head" ++ ": empty list!"
于 2020-11-02T21:52:51.350 回答