如何在Haskell转换过程中保留原生循环列表结构?

时间:2016-07-25 09:22:30

标签: haskell graph time-complexity cyclic-dependency tying-the-knot

我正在使用“打结”技术研究Haskell中的图形式事物处理。我想,循环列表只是一种无限列表内部实现,所以在理想世界中我们不应该关心subj。但它可能会对计算复杂性产生巨大影响,请考虑一下具有循环世界的一维元胞自动机:

ribbon = let x = 0 : y
             y = 1 : x
         in  x

update_cycle :: Num a => [a] -> [a]
update_cycle lst@(_:xs) = ( f lst : update_cycle xs)
update_cycle []         = error "infinite cycle assumed"

f :: Num a => [a] -> a           --  some arbitrary list reduction
f (x:(y:_)) = traceShow "f called" $ x - y

这是一个只有两个单元格的循环。让我们迈出一步:

*Main> take 2 $ update_cycle ribbon
[-1,1]
"f called"
"f called"

这很好,现在分两步:

*Main> take 2 $ (update_cycle . update_cycle) ribbon
[-2,2]
"f called"
"f called"
"f called"
"f called"
"f called"

这是五次调用而不是四次调用,实际上意味着每一步调用次数增加,因此我们在总步数而不是线性上有二次复杂度。我可以将循环显式化,如下所示:

newtype UserDefCyclic a = UserDefCyclic { fromTC :: [a] }

udcToList :: UserDefCyclic a -> [a]
udcToList (UserDefCyclic x) = cycle x

update_udc :: Num a => UserDefCyclic a -> UserDefCyclic a
update_udc (UserDefCyclic core) = UserDefCyclic $ take (length core) (update_cycle ( cycle core )) 

但它很难看,而我真的对像图形这样的更复杂的结构感兴趣。 问题是:有没有办法让这里的代码既好又快?或者希望编译器在一些光明的未来能够更好地处理上面的代码吗?

0 个答案:

没有答案