Haskell宏从他们的名字到一些表达式创建一个Map?

时间:2018-02-27 03:08:58

标签: haskell macros introspection template-haskell

我有一些变量ab。我想通过键入Data.Map.fromList [("a",a),("b",b)]之类的内容快速创建地图magic [a,b]。我想在GHCI中这样做,而不是在模块中。

我花了一些时间学习模板Haskell,但我仍然无法判断它是否可能。是吗?

1 个答案:

答案 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)) |]