【问题标题】:Function to output function name输出函数名的函数
【发布时间】:2013-03-07 13:16:11
【问题描述】:

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

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

【问题讨论】:

  • 没有。由于其多态类型,(a -> b) -> String 类型的函数无法检查其参数(超出seqing 或将其应用于底部)。因此它无法确定它的论点。
  • 如果一个函数返回它自己的函数名,类型会不会是() -> String(而且实现相当简单)?
  • Haskell 中的大多数函数甚至没有名字。可能存在的东西是显示表达式类型的函数,尽管我怀疑这会非常有用。
  • 如果你有这样的功能,你会用它做什么?您的问题可能有更简单的解决方案。
  • 除了 Daniel Fischer 所说的之外,这将违反等式推理:let f = id in findName f 可能会产生 "f",但 findName id 可能会产生 "id"。这都与函数根本没有名称这一事实有关。变量可以在具有函数类型的范围内,仅此而已。

标签: haskell metaprogramming template-haskell


【解决方案1】:

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

这不可能没有元编程,这通常表明你做错了:)。 但假设你不是,实现正确方向的一种方法是通过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)"

现在我们对变量了解很多。因此,您可以通过将 Name 传递给函数(通过 'f)而不是 f 本身来玩游戏。

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

【讨论】:

    【解决方案2】:

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

    let f x = x
        g   = f
        h   = f
    in  getName g == getName h
    

    【讨论】:

      【解决方案3】:

      我不知道您需要它来做什么,但也许一个简单的解决方案就足够了?像这样:

      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 等版本,以后您肯定会遇到其他问题,但也许这就是您所需要的...

      【讨论】:

        【解决方案4】:

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

        Prelude> let myNameIs::(a->b) -> String; myNameIs f = "myNameIs"
        Prelude> :type myNameIs
        myNameIs :: (a -> b) -> String
        Prelude> myNameIs myNameIs
        "myNameIs"
        

        【讨论】:

          【解决方案5】:

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

          #define _NAMEOF(name) #name
          

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

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

          哪个 CPP 应该翻译成有效的 Haskell 源代码行:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-11-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多