ZipN

率直な感想…構文木を作るコード書くのめんどくさすぎ…

自分で書こうと思っても全然書けない。

慣れの問題なのだろうか…?
2004-12-27

構文木」というのを意識しすぎなのだと思います。

  • 例3 任意個のzip

(引用略)

zip3 = $(zipN 3)

と書ければ嬉しいという話。

の zipN と zipWithN を書いてみました。

{-# OPTIONS -fth #-}
module ZipN where
import Language.Haskell.TH

zipN n = [| $(zipWithN n) $(tupN n) |]

zipWithN n = [| \f x -> $(g (n - 1)) (map f x) |]
  where g 0 = [| id |]
        g n = [| \x y -> $(g (n - 1)) (zipWith ($) x y) |]

tupN :: Int -> ExpQ
tupN n = do nms <- sequence (replicate n (newName "x"))
            lamE (map varP nms) (tupE (map varE nms))

すごく簡単でしょう?
私は Template Haskell はかなり使いやすくてしかも強力なmeta-programmingシステムだと思います。

捕捉

本当はこれでもいいはずなのだが、存在しないGHC.Tuple.(,,,*)を参照しているというバグのために動作しない。

tupN n = [| $(conE (tupleDataName n)) |]

ghc-6.2.2の場合、newNameがない:

{-# OPTIONS -fth #-}
module ZipN622 where
import Language.Haskell.THSyntax

zipN n = [| $(zipWithN n) $(tupN n) |]

zipWithN n = [| \f x -> $(g (n - 1)) (map f x) |]
  where g 0 = [| id |]
        g n = [| \x y -> $(g (n - 1)) (zipWith ($) x y) |]

tupN :: Int -> ExpQ
tupN n = do nms <- gensyms n "x"
            lamE (map varP nms) (tupE (map varE nms))

gensyms 0 s = return []
gensyms n s = do  s' <- gensym s 
                  xs <- gensyms (n - 1) s'
                  return (s':xs)