2

假设我想在 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)!

4

4 回答 4

3

正如@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 ]
于 2015-05-11T18:08:37.577 回答
2

我认为你对你真正想要的东西有点困惑。标识符的名称c只是"c"; 打印没有问题。

我假设您真正想要的是消除模块中的重复["c", "e", "eV", "h", "hbar", "nm", "k"][c,e,eV,h,hbar,nm,k]. 具体来说,您打算如何做到这一点?然后我们可以讨论它是否可以在 Haskell 中工作。

可能会归结为以下一项或两项

  1. 缺乏eval. 如果您保留 list ["c", "e", "eV", "h", "hbar", "nm", "k"],您可能希望评估这些字符串以找出相应变量的值。虽然您可能会在程序中嵌入 Haskell 解释器,但正如其他人所指出的那样,在运行时不一定有名称"c", "e", ... 到它们的值的任何映射,因此您不能从字符串"c"转到值2.99792458e8

  2. 参考透明度。您可以保留该列表[c,e,eV,h,hbar,nm,k]并希望找到一些神奇的方法来从中恢复字符串"c", "e", ... 。但这也是不可能的。[c,e,eV,h,hbar,nm,k]只是一个 Doubles 列表,因为c = 2.99792458e8,我们也有[c,e,eV,h,hbar,nm,k] = [2.99792458e8,e,eV,h,hbar,nm,k],并且没有办法"c"从后者中提取。

于 2015-05-11T20:37:46.127 回答
2

假设我想在 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])
                    )

                )
        )

putStrfoldl、和是在 GHC 附带的模块中定义的函数map,并且与您的程序分开编译。这些函数无法知道变量的名称——它们得到的只是它们的值。zipWithshow

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

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

于 2015-05-11T21:41:58.533 回答
2

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

如果您正在处理一堆相同类型的事物,那么您很幸运——您可以使用 aMap或 trie 将名称与值连接起来。如果您需要各种类型的东西,您的生活就会变得更加复杂——例如,参见HList 记录

综上所述,我认为你应该仔细考虑一下你到底有多想要这个。这有点不寻常。

于 2015-05-12T01:17:22.343 回答