Reputation: 3709
I have some variables a
and b
. I want to create the map Data.Map.fromList [("a",a),("b",b)]
rapidly, by typing something like magic [a,b]
. I want to do this live in GHCI, not from within a module.
I spent some time learning Template Haskell for this, but I still can't even tell if it's possible. Is it?
Upvotes: 2
Views: 114
Reputation: 27003
Ok, here's a very quick and dirty implementation of 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)) |]
Here is using it in 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)]’
Note that template haskell is enabled in ghci, and the $()
splice syntax is used to tell it to actually splice the generated expression in. Also note the compile error in the case where not every list entry would have the same type.
This code is quick and dirty, but the happy path is correct. Error cases result in code that fails to splice, but not necessarily with the friendliest error messages. All in all... it's a starting point.
Edit - Version with minimal input keystrokes, as described in the comments below:
{-# 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)) |]
Upvotes: 5