我在寻找hylomorhism示例时遇到了@amalloy 关于 SO 的一篇不错的帖子,它通过有用的讨论和完整的实现来说明递归方案 (RS) 的使用:
{-# LANGUAGE DeriveFunctor #-}
import Control.Arrow ( (>>>), (<<<) )
newtype Term f = In {out :: f (Term f)}
type Algebra f a = f a -> a
type Coalgebra f a = a -> f a
cata :: (Functor f) => Algebra f a -> Term f -> a
cata fn = out >>> fmap (cata fn) >>> fn
ana :: (Functor f) => Coalgebra f a -> a -> Term f
ana f = In <<< fmap (ana f) <<< f
hylo :: Functor f => Algebra f b -> Coalgebra f a -> a -> b
hylo alg coalg = ana coalg >>> cata alg
data ChangePuzzle a = Solved Cent
| Pending {spend, forget :: a}
deriving Functor
type Cent = Int
type ChangePuzzleArgs = ([Cent], Cent)
coins :: [Cent]
coins = [50, 25, 10, 5, 1]
divide :: Coalgebra ChangePuzzle ChangePuzzleArgs
divide (_, 0) = Solved 1
divide ([], _) = Solved 0
divide (coins@(x:xs), n) | n < 0 = Solved 0
| otherwise = Pending (coins, n - x) (xs, n)
conquer :: Algebra ChangePuzzle Cent
conquer (Solved n) = n
conquer (Pending a b) = a + b
waysToMakeChange :: ChangePuzzleArgs -> Int
waysToMakeChange = hylo conquer divide
该代码按预期工作。尽管已经对 RS 方面有了一些模糊的直觉,但我仍然想知道:
- 因为这是关于计算组合,为什么
Solved Cent而不是Solved Int?(如果这是一个合理的问题,这可能听起来像一个小问题,但我希望它可能是下面其余不确定性的根源,尽管我怀疑我错过了一些更基本的东西!)。 - 因为我们稍后在 中求和,所以
divide0/1Solved大概表示失败/成功? - 在 中,添加和是
conquer什么意思?这两个值(作为s)表示什么,在这种情况下它们的总和意味着什么?abPendingCent - 在 中
conquer,我原以为我们只需要对Solveds 求和,作者就谈到了这一点,但目前尚不清楚这个Pending案例是如何起作用的(例如,修复conquer (Pending a b) = 11确实对功能产生不利影响,这可能是一个线索waysToMakeChange返回,11或该情况固定为的任何常数)。 - in
conquer,aandbareCents, 而 individetheyreChangePuzzleArgs(aka([Cent], Cent)) - 转换发生在哪里?
注意:作为新手,我无法在原始答案下方发表评论,这可能更合适,但我希望这也是有用的。