THでzip製作

論文にのってたので、Quoted-Monad使わない方向性で書いた。
ていうか、[| \x -> x |]とかで書いて、$つけるとか意味分からんので。
それとdoc読まないでいきなり書いてるから未だにさーぱり分からん。

module Th_ZipN3 where

import Language.Haskell.TH
import Language.Haskell.TH.Lib
import GHC.Base

{-
$(zipN 3) as bs cs
っぽく
-}

zipN n = [| let zp = $(do return (mkZip n (VarE $ mkName "zp"))) in zp |]

-- mkZip :: Int -> Exp -> Exp
mkZip n name = LamE pYs (CaseE (TupE eYs) [m1,m2])
    where
      (pXs, eXs)  = genPE "x"  n
      (pYs, eYs)  = genPE "y"  n
      (pXSs,eXSs) = genPE "xs" n
      pcons x xs  = InfixP x (mkName "GHC.Base.:") xs
      m1 = simpleMatch (TupP (zipWith pcons pXs pXSs)) (InfixE (Just(TupE eXs)) (ConE $ mkName "GHC.Base.:") (Just (apply' name eXSs)))
      m2 = simpleMatch (TupP (replicate n WildP)) (ConE (mkName "GHC.Base.[]"))

genPE :: String -> Int -> ([Pat],[Exp])
genPE s n = let ns = [ s++(show i) | i <- [1..n]]
            in (map (\x -> VarP $ mkName x) ns,map (\x -> VarE $ mkName x) ns)

apply' :: Exp -> [Exp] -> Exp
apply' fun (x:[]) = AppE fun x
apply' fun (x:xs) = apply' (AppE fun x) xs

でまぁこれが落ちると。後どうやって再帰させたもんだか分からんという感じで困って授業に行く気が完全に無く成った。


pprintするとこんな感じにはなってくれるんだけどもなぁ。

\y1 y2 y3 -> case (y1, y2, y3) of
                 (x1 GHC.Base.: xs1, x2 GHC.Base.: xs2, x3 GHC.Base.: xs3) -> (x1,
                                                                               x2,
                                                                               x3) GHC.Base.: zp xs1 xs2 xs3
                 (_, _, _) -> GHC.Base.[]

(do return zp) >>= putStrLn . pprint

動いた

module Th_ZipN4 where

import Language.Haskell.TH
import Language.Haskell.TH.Lib
import GHC.Base

zipN n = [| let zp = $(mkZip n $ var "zp") in zp |]

var str = varE $ mkName str
pvar str = varP $ mkName str

genPE :: String -> Int -> ([PatQ],[ExpQ]) 
genPE s n = let ns = [ s++(show i) | i <- [1..n]] 
            in (map pvar ns, map var ns)

mkZip n name = lamE pYs (caseE (tupE eYs) [m1,m2])
    where 
      (pXs, eXs) = genPE "x" n 
      (pYs, eYs) = genPE "y" n 
      (pXSs,eXSs) = genPE "xs" n

      pcons :: PatQ -> PatQ -> PatQ
      pcons x xs = infixP x (mkName "GHC.Base.:") xs

      simpleM p e = match p (normalB e) []
      b = [| $(tupE eXs) : $(appsE (name : eXSs)) |] 
      m1 = simpleM (tupP (zipWith pcons pXs pXSs)) b 
      m2 = simpleM (tupP (replicate n wildP)) (conE $ mkName "GHC.Base.[]")

importして、$(zipN なんか数字)やったら出来る。素晴らしい。


けど、これ今のTHに合う様に論文を書き直しただけで、個人的にはSyntax Suger使っていない方で書きたいんだけど、何故だか動いてくれない。
こんなのが出ている。

    GHC stage restriction: `n'
      is used in a top-level splice, and must be imported, not defined locally

慎重に調べる

ghciで

let myZipN n = [| let zp = $(do return $ mkZip n (VarE $ mkName "zp")) in zp |]

こんなんをやると通るんだけど、その次が問題で

*Th_ZipN3> $(myZipN 3)

<interactive>:1:2: Not in scope: `zp'

ぬへー。


一方、例えば

let zp = $(do return (mkZip 3 (VarE $ mkName "zp")))
$(do return (mkZip 3 (VarE $ mkName "zp")))

こんな事をすれば動く。


そういう事ならば、と別モジュールで

zipN2 n = do let zp = $(do return $ mkZip n (VarE $ mkName "zp"))
             $(do return $ mkZip n (VarE $ mkName "zp"))

とか取りあえず書いてみると、ここで

GHC stage restriction: `n'

が出て来る。