我在寻找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
?(如果这是一个合理的问题,这可能听起来像一个小问题,但我希望它可能是下面其余不确定性的根源,尽管我怀疑我错过了一些更基本的东西!)。 - 因为我们稍后在 中求和,所以
divide
0/1Solved
大概表示失败/成功? - 在 中,添加和是
conquer
什么意思?这两个值(作为s)表示什么,在这种情况下它们的总和意味着什么?a
b
Pending
Cent
- 在 中
conquer
,我原以为我们只需要对Solved
s 求和,作者就谈到了这一点,但目前尚不清楚这个Pending
案例是如何起作用的(例如,修复conquer (Pending a b) = 11
确实对功能产生不利影响,这可能是一个线索waysToMakeChange
返回,11
或该情况固定为的任何常数)。 - in
conquer
,a
andb
areCent
s, 而 individe
theyreChangePuzzleArgs
(aka([Cent], Cent)
) - 转换发生在哪里?
注意:作为新手,我无法在原始答案下方发表评论,这可能更合适,但我希望这也是有用的。