如何在Haskell中打印标识符或绑定的名称?

如何在Haskell中打印标识符或绑定的名称?,haskell,metaprogramming,code-inspection,Haskell,Metaprogramming,Code Inspection,我想打印Haskell中“变量”的名称和值。该名称在编译时已知!有没有比下面的例子更好的方法 module V (e, c, eV, h, hbar, nm, k, viewAllConstants) where import Text.Printf c = 2.99792458e8::Double e = exp(1) eV = 1.602176565e-19 h = 6.62606957e-34 hbar = h/(2*pi) nm = 1e-9 k = 1.3806488e-23 view

我想打印Haskell中“变量”的名称和值。该名称在编译时已知!有没有比下面的例子更好的方法

module V
(e, c, eV, h, hbar, nm, k, viewAllConstants) where
import Text.Printf
c = 2.99792458e8::Double
e = exp(1)
eV = 1.602176565e-19
h = 6.62606957e-34
hbar = h/(2*pi)
nm = 1e-9
k = 1.3806488e-23
viewAllConstants = do
    putStr ((\a b -> (foldl (++) "" ( zipWith (++) a (map (printf " = %.2e\n") b))))
        ["c", "e", "eV", "h", "hbar", "nm", "k"]
        [c, e, eV, h, hbar, nm, k] )
请在您的答案中发布一个工作代码示例(runhaskell)

正如@PeterHall所说:


在Lisp中,数据和代码之间的区别是模糊的,所有内容在运行时都是可检查和动态的。在Haskell中,所有类型和绑定名称都会在编译时删除,这允许进行大量优化

换句话说,该名称在运行时不为人所知

此外,这些不是“变量”,而是常量,或者如前所述,是绑定。因此,访问绑定的名称没有意义,因为它永远不会更改

正如@MathematicalOrchid所建议的,可能有一个模板Haskell解决方案,尽管它可能只是相对有用的

关于打印绑定的更好方法,请尝试以下方法:

import Control.Monad (forM_)

viewAllConstants = forM_ (\(a, b) -> putStrLn (a ++ " = " ++ show b)) 
                   $ zip ["c", "e", "eV", "h", "hbar", "nm", "k"] 
                         [ c,   e,   eV,   h,   hbar,   nm,   k ]

我觉得你对自己真正想要的东西有点困惑。标识符
c
的名称就是
“c”
;打印出来没有问题

我假设您真正想要的是消除模块中
[“c”、“e”、“eV”、“h”、“hbar”、“nm”、“k”]
[c、e、eV、h、hbar、nm、k]
之间的重复。具体来说,你打算怎么做?然后我们可以讨论它是否能在Haskell中工作

可能会归结为以下两种情况中的一种或两种

  • 缺少
    eval
    。如果您保留列表
    [“c”、“e”、“eV”、“h”、“hbar”、“nm”、“k”]
    ,您可能希望计算这些字符串以找出相应变量的值。虽然可以在程序中潜在地嵌入Haskell解释器,但在运行时不一定存在名称
    “c”
    “e”
    。。。正如其他人所指出的那样,您不能从字符串
    “c”
    转到值
    2.99792458e8

  • 参考透明度。您可以保留列表
    [c,e,eV,h,hbar,nm,k]
    ,并希望找到一些神奇的方法来恢复字符串
    “c”
    “e”
    。。。从它。但这也是不可能的<代码>[c,e,eV,h,hbar,nm,k]只是一个双倍列表,由于
    c=2.99792458e8
    ,我们也有
    [c,e,eV,h,hbar,nm,k]=[2.99792458e8,e,eV,h,hbar,nm,k]
    ,无法从后者中提取
    “c”

  • 我想打印Haskell中“变量”的名称和值。该名称在编译时已知

    该名称在某些作用域中是已知的,而在其他作用域中是未知的。这是至关重要的。让我们看看您的示例代码:

    module V (e, c, eV, h, hbar, nm, k, viewAllConstants) where
    
    c = 2.99792458e8
    e = exp(1)
    eV = 1.602176565e-19
    h = 6.62606957e-34
    hbar = h/(2*pi)
    nm = 1e-9
    k = 1.3806488e-23
    
    viewAllConstants = do
        putStr (foldl (++) "" (map ("\n" ++)
                        ( zipWith (++) ["c", "e", "eV", "h", "hbar", "nm", "k"]
                            (map ((" = " ++) . show) [c,e,eV,h,hbar,nm,k])
                        )
    
                    )
            )
    
    putsr
    foldl
    map
    zipWith
    show
    是GHC随附的模块中定义的函数,它们与您的程序分开编译。这些函数无法知道变量的名称,它们得到的只是它们的值

    请注意,与Peter Hall的评论相反,这并不是Haskell与Lisp的区别。在Lisp中,过程的参数通过引用传递给值,而不是符号;Lisp函数不比Haskell函数更了解其参数的名称


    此外,您还可以将任意表达式作为参数传递给两种语言中的函数。这些值没有绑定到调用站点中的变量。

    您可以这样做!你不能像你想的那样做。一些语言实现使用字典来表示表达式的计算环境。一些更愚蠢的人向程序员公开了这种机制。这是愚蠢的,因为它阻止了实现者在将来转向更快的技术。Haskell不会做任何类似的事情,除了可能在类型检查器中。但这并不能阻止你自己建立和使用这样的词典

    如果您处理的是一系列相同类型的事情,那么幸运的是,您可以使用
    Map
    或trie将名称与值连接起来。如果你需要各种各样的东西,你的生活会变得更复杂,例如


    尽管如此,我认为你应该仔细考虑你到底有多想要这个。这有点不寻常。

    在Lisp中可能存在重复,数据和代码之间的区别很模糊,所有内容在运行时都是可检查和动态的。在Haskell中,所有类型和绑定名称在编译时都会被删除,这允许进行大量优化?根据您的具体要求,Template Haskell可能有帮助,也可能没有帮助。@MathematicalArchid我认为现在的问题更好地反映了我想做的事情:打印绑定/标识符的名称,而不是值。该名称在编译时已知@PeterHall:Lisp函数只接收对其参数值的引用。它只知道Haskell函数执行调用方将这些值绑定到的标识符(如果有!)。当然,该名称在编译时已知。。。我想你是想说些别的,但我不太清楚是什么。@ReidBarton哇,这是运行时!编辑。