関数引数のpermutation (4)
いつまで引っ張るのかという感じですが…
型をrefineするcast*1が安全だと仮定すると、このように動くものが書ける。
*FunArgPerm2> [f 1 2 3 | f <- permArgsMono 3 (\a b c -> [a, b, c :: Int])] [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] *FunArgPerm2> [f 1 2 3 | f <- permArgsMono 2 (\a b c -> [a, b, c :: Int])] [[1,2,3],[2,1,3]] *FunArgPerm2> [f 1 2 3 | f <- permArgsMono 4 (\a b c -> [a, b, c :: Int])] *** Exception: permArgsMono
*FunArgPerm2> [f 1 2 3 | f <- unsafePermArgs 3 (,,)] [(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1)] *FunArgPerm2> [f 1 2 3 | f <- unsafePermArgs 4 (,,)] [(1,2,3),(zsh: segmentation fault ghci
以下のコードはGHCi, Hugsでは動くようだ。GHCは確認していない。
{-# OPTIONS -fglasgow-exts #-} module FunArgPerm2 where import Data.Dynamic import Data.Typeable import System.IO.Unsafe (unsafePerformIO) import Data.IORef (readIORef, writeIORef, IORef, newIORef) permArgsMono n f | checkType n f = unsafePermArgs n f | otherwise = error "permArgsMono" checkType n f = n >= 1 && length as > n && (all (== head as) $ take n as) where as = typeRepFunArgs (typeOf f) unsafePermArgs n f = map ($ f) $ g $ map unMyDyn (encode n) where g [] = [id] g xxs@(x:xs) = [r . j| r <- subs xxs, j <- g xs] subs xs = scanl (flip (.)) id xs encode n = take (n - 1) $ iterate next (MyDyn flip) next (MyDyn g) = MyDyn ((.) g) data MyDyn = forall a b. MyDyn (a -> b) unMyDyn (MyDyn x) = unsafeCast x -- cast unsafeCast x = unsafePerformIO $ writeIORef castref x >> readIORef castref castref = unsafePerformIO $ newIORef undefined -- Hugs Nov 2003 では typeRepArgs を typerepArgs に。 typeRepFunArgs t = f (typeRepArgs t) where f [b] = [b] f [a, b] = a:f (typeRepArgs b)
関連
*1:id :: a -> a を id :: (a -> b) -> (a -> b) にするようなcastのこと