我正在使用“打结”技术研究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 ))
但它很难看,而我真的对像图形这样的更复杂的结构感兴趣。 问题是:有没有办法让这里的代码既好又快?或者希望编译器在一些光明的未来能够更好地处理上面的代码吗?