関数引数のpermutation (3)

今度は [a b c, a c b, ...] に \a b c -> f をmapするというとてもマクロ的な作戦。

x <- newName str

で作った変数はschemeのマクロのように変数の衝突を回避するけれど、

mkName str

で作った変数は文字どおりstrのままでダイナミックスコープ。

permArgs' :: Int -> ExpQ
permArgs' n = [| \f -> $( 
      do  -- 変数(a, b, c..)の生成
          nms <- sequence $ replicate n $ newName "x"
          listE $ 
            -- \[a, b, c] -> (\a b c -> f a b c)
            map (\vars -> lamE (map varP nms) (appsE (varE (mkName "f"):vars)))
              -- [a, b, c] -> [[a, b, c], [a, c, b],...]
              $ [ map varE nms' | nms' <- perm nms ]
    ) |]

appsE :: [ExpQ] -> ExpQ
appsE = foldl1 appE

perm [] = [[]]
perm xs = [(y:ys) | y <- xs, ys <- perm $ delete y xs]