如何在 Haskell 中打印标识符或绑定的名称?
How can one print the name of an identifier or binding in Haskell?
假设我想在 Haskell 中打印 "variable" 的名称和值。该名称在编译时已知!有没有比以下示例更好的方法?
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] )
请post在您的回答中提供一个工作代码示例 (runhaskell)!
正如@PeterHall 所说:
In Lisp, the distinction between data and code is blurred and everything is inspectable and dynamic at runtime. In Haskell, all types and binding names are erased at compile time, which allows for a huge amount of optimisation.
换句话说,名称在运行时不已知。
此外,这些不是'variables',它们是常量,或者如前所述,绑定。出于这个原因,能够访问绑定的名称没有意义,因为它永远不会改变。
正如@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]
只是一个 Double 的列表,因为 c = 2.99792458e8
,我们也有 [c,e,eV,h,hbar,nm,k] = [2.99792458e8,e,eV,h,hbar,nm,k]
,并且无法从后者中提取 "c"
。
Supose I want to print the name and the value of a "variable" in Haskell. The name is known at compile time!
该名称在某些范围中已知,而在其他范围中则未知。这很关键。让我们看看您的示例代码:
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])
)
)
)
putStr
、foldl
、map
、zipWith
和 show
是在 GHC 附带的模块中定义的函数,并且与您的代码分开编译程序。这些函数无法知道您的变量的名称——传递给它们的只是它们的值。
请注意,与 Peter Hall 的评论相反,这并不是 Haskell 与 Lisp 的区别。在 Lisp 中,过程的参数通过引用传递给值,而不是传递给符号;与 Haskell 函数相比,Lisp 函数不再知道其参数的名称。
此外,您可以将任意表达式作为参数传递给两种语言的函数。这些值未绑定到调用站点中的变量。
你可以的!你只是不能像你想的那样去做。一些语言实现使用字典来表示计算表达式的环境。一些比较愚蠢的人将这种机制暴露给程序员。这是愚蠢的,因为它阻止了实现者在未来切换到更快的技术。 Haskell 不会做任何类似的事情,除了可能在类型检查器中。但这并不能阻止您自己构建和使用此类词典!
如果您正在处理一堆相同类型的事物,那么您很幸运 — 您可以使用 Map
或 trie 树将名称与值联系起来。如果您需要各种类型的东西,您的生活就会变得更加复杂——例如参见 [=11=]。
综上所述,我认为你应该仔细考虑一下你到底有多想要这个。这有点不寻常。
假设我想在 Haskell 中打印 "variable" 的名称和值。该名称在编译时已知!有没有比以下示例更好的方法?
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] )
请post在您的回答中提供一个工作代码示例 (runhaskell)!
正如@PeterHall 所说:
In Lisp, the distinction between data and code is blurred and everything is inspectable and dynamic at runtime. In Haskell, all types and binding names are erased at compile time, which allows for a huge amount of optimisation.
换句话说,名称在运行时不已知。
此外,这些不是'variables',它们是常量,或者如前所述,绑定。出于这个原因,能够访问绑定的名称没有意义,因为它永远不会改变。
正如@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]
只是一个 Double 的列表,因为c = 2.99792458e8
,我们也有[c,e,eV,h,hbar,nm,k] = [2.99792458e8,e,eV,h,hbar,nm,k]
,并且无法从后者中提取"c"
。
Supose I want to print the name and the value of a "variable" in Haskell. The name is known at compile time!
该名称在某些范围中已知,而在其他范围中则未知。这很关键。让我们看看您的示例代码:
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])
)
)
)
putStr
、foldl
、map
、zipWith
和 show
是在 GHC 附带的模块中定义的函数,并且与您的代码分开编译程序。这些函数无法知道您的变量的名称——传递给它们的只是它们的值。
请注意,与 Peter Hall 的评论相反,这并不是 Haskell 与 Lisp 的区别。在 Lisp 中,过程的参数通过引用传递给值,而不是传递给符号;与 Haskell 函数相比,Lisp 函数不再知道其参数的名称。
此外,您可以将任意表达式作为参数传递给两种语言的函数。这些值未绑定到调用站点中的变量。
你可以的!你只是不能像你想的那样去做。一些语言实现使用字典来表示计算表达式的环境。一些比较愚蠢的人将这种机制暴露给程序员。这是愚蠢的,因为它阻止了实现者在未来切换到更快的技术。 Haskell 不会做任何类似的事情,除了可能在类型检查器中。但这并不能阻止您自己构建和使用此类词典!
如果您正在处理一堆相同类型的事物,那么您很幸运 — 您可以使用 Map
或 trie 树将名称与值联系起来。如果您需要各种类型的东西,您的生活就会变得更加复杂——例如参见 [=11=]。
综上所述,我认为你应该仔细考虑一下你到底有多想要这个。这有点不寻常。