3

我尝试在 Haskell 中打印函数只是为了好玩,比如这个例子:

{-# LANGUAGE FlexibleInstances #-}

instance Show (Int -> Bool) where
    show _ = "function: Int -> Bool"

加载 GHCi 并运行示例:

λ> :l foo
[1 of 1] Compiling Main             ( foo.hs, interpreted )

foo.hs:2:1: Warning: Unrecognised pragma
Ok, modules loaded: Main.
λ> (==2) :: Int -> Bool
function: Int -> Bool

但是,我希望看到每个函数都在调用时打印自己。

4

2 回答 2

9

您不能将其用于一般函数,因为类型信息仅在编译时出现,但Typeable如果类型是类的实例,则使用类来编写足够接近的内容Typeable

import Data.Typeable

instance (Typeable a, Typeable b) => Show (a -> b) where
    show f = "Function: " ++ (show $ typeOf f)

在 ghci 中测试这个

*Main> (+)
Function: Integer -> Integer -> Integer
*Main> (+10)
Function: Integer -> Integer

但这不适用于一般函数,直到类型被限制为具有Typeable实例的类型。

*Main> zip

<interactive>:3:1:
    Ambiguous type variable `a0' in the constraint:
      (Typeable a0) arising from a use of `print'
    Probable fix: add a type signature that fixes these type variable(s)
    In a stmt of an interactive GHCi command: print it

<interactive>:3:1:
    Ambiguous type variable `b0' in the constraint:
      (Typeable b0) arising from a use of `print'
    Probable fix: add a type signature that fixes these type variable(s)
    In a stmt of an interactive GHCi command: print it
*Main> zip :: [Int] -> [Bool] -> [(Int,Bool)]
Function: [Int] -> [Bool] -> [(Int,Bool)]
于 2012-10-14T07:19:46.520 回答
7

我假设您希望该show方法打印函数的地址,这就是 Python 所做的:

>>> def foo(a):
...     return a
... 
>>> print foo
<function foo at 0xb76f679c>

确实没有支持的方法(Haskell 是一种安全的高级语言,它从函数指针等低级细节中抽象出来),除非您愿意使用内部 GHC 函数unpackClosure#

{-# LANGUAGE MagicHash,UnboxedTuples,FlexibleInstances #-}
module Main
       where

import GHC.Base
import Text.Printf

instance Show (a -> a) where
  show f = case unpackClosure# f of
    (# a, _, _ #) -> let addr = (I# (addr2Int# a))
                     in printf "<function ??? at %x>" addr

main :: IO ()
main = print (\a -> a)

测试:

$ ./Main 
<function ??? at 804cf90>

不幸的是,没有办法获得函数的名称,因为它根本不存在于编译的可执行文件中(可能有调试信息,但你不能指望它的存在)。如果您的函数可以从 C 中调用,您还可以使用 C 帮助程序获取其地址。

于 2012-10-14T05:49:41.237 回答