能否对递归方案进行记忆化?如果可以,应该如何实现?
例如,以下代码使用了anamorphism和catamorphism。
newtype Fix f = In (f (Fix f))
deriving instance (Eq (f (Fix f))) => Eq (Fix f)
deriving instance (Ord (f (Fix f))) => Ord (Fix f)
deriving instance (Show (f (Fix f))) => Show (Fix f)
out :: Fix f -> f (Fix f)
out (In f) = f
-- Catamorphism
type Algebra f a = f a -> a
cata :: (Functor f) => Algebra f a -> Fix f -> a
cata f = f . fmap (cata f) . out
-- Anamorphism
type Coalgebra f a = a -> f a
ana :: (Functor f) => Coalgebra f a -> a -> Fix f
ana f = In . fmap (ana f) . f
解决格子路径问题:
latticePaths m n = cata countPathsAlgNoMemo (ana buildLattice (m, n))
-- recursive solution without dynamic programming
buildLattice :: (Int, Int) -> LeafBTreeF Int (Int, Int)
buildLattice (m, n)
| m == 0 && n == 0 = LeafBTreeLeafF 1
| m < 0 || n < 0 = LeafBTreeLeafF 0
| otherwise = LeafBTreeNodeF (m - 1, n) (m, n - 1)
countPathsAlgNoMemo :: LeafBTreeF Int Int -> Int
countPathsAlgNoMemo (LeafBTreeLeafF n) = n
countPathsAlgNoMemo (LeafBTreeNodeF a b) = a + b
这种方法效率低下,因为子问题没有被存储和重复使用而是重新计算。我想知道是否有一种方法可以存储(或让Haskell编译器存储)先前计算过的子问题。
我查看了一些与记忆化多态函数相关的资源(http://blog.sigfpe.com/2009/11/memoizing-polymorphic-functions-with.html,http://conal.net/blog/posts/memoizing-polymorphic-functions-part-two),但是还没有能够理解它们如何适用于此处。
注意:我特别关注apomorphism/paramorphism
和anamorphism/catamorphism
是否可以进行记忆化(或者是否有其他解决方案可以使用这些递归方案来存储子问题)。我知道histomorphism和dynamorphism适合解决动态规划问题,但出于我的目的,我想将重点限制在apo/para或ana/cata上。
我的paramorphism
和apomorphism
:
-- Paramorphism
type RAlgebra f a = f (Fix f, a) -> a
para :: (Functor f) => RAlgebra f a -> Fix f -> a
para rAlg = rAlg . fmap fanout . out
where fanout t = (t, para rAlg t)
-- Apomorphism
type RCoalgebra f a = a -> f (Either (Fix f) a)
apo :: Functor f => RCoalgebra f a -> a -> Fix f
apo rCoalg = In . fmap fanin . rCoalg
where fanin = either id (apo rCoalg)
anamorphism
之后的catamorphism
很有效,但是同样的想法能否用于apomorphism
之后的paramorphism
呢?我已经在问题中添加了两者的定义。目前我在h = rAlg.fmap (fanout.fanin).rCoalg
处卡住了。 - cocorudeboy