我有一些变量a
和b
。我想通过键入Data.Map.fromList [("a",a),("b",b)]
之类的内容快速创建地图magic [a,b]
。我想在GHCI中这样做,而不是在模块中。
我花了一些时间学习模板Haskell,但我仍然无法判断它是否可能。是吗?
答案 0 :(得分:5)
好的,这是magic
的一个非常快速和肮脏的实现:
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
import qualified Data.Map as M
magic :: [String] -> ExpQ
magic xs = [| M.fromList $(listE (map toPair xs)) |]
where
toPair nameStr = do
Just name <- lookupValueName nameStr
[| (nameStr, $(varE name)) |]
这是在ghci中使用它:
$ ghci -XTemplateHaskell thmagic.hs
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling Main ( thmagic.hs, interpreted )
Ok, one module loaded.
*Main> let x = 1 ; y = 2 ; z = "hello"
*Main> $(magic ["x", "y"])
fromList [("x",1),("y",2)]
*Main> $(magic ["x", "y", "z"])
<interactive>:3:3: error:
• No instance for (Num [Char]) arising from a use of ‘x’
• In the expression: x
In the expression: ("x", x)
In the first argument of ‘M.fromList’, namely
‘[("x", x), ("y", y), ("z", z)]’
请注意,在ghci中启用了模板haskell,并使用$()
splice语法告诉它实际拼接生成的表达式。还要注意在不是每个列表条目都具有的情况下的编译错误同类型。
这段代码快速而且脏,但幸福的道路是正确的。错误情况导致代码无法拼接,但不一定导致最友好的错误消息。总而言之......这是一个起点。
编辑 - 具有最少输入击键的版本,如下面的评论中所述:
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
import qualified Data.Map as M
magic :: String -> ExpQ
magic names = [| M.fromList $(listE (map toPair (words names))) |]
where
toPair nameStr = do
Just name <- lookupValueName nameStr
[| (nameStr, $(varE name)) |]