【发布时间】:2022-01-16 20:49:15
【问题描述】:
我在寻找 @amalloy 的 SO 上的 a nice post 时遇到了 hylomorhism 示例,这些示例通过有用的讨论和完整的实现来说明递归方案 (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、Solved0/1 大概表示失败/成功? - 在
conquer中,添加Pending的a和b是什么意思?这 2 个值(如Cents)表示什么,它们的总和在这种情况下意味着什么? - 在
conquer中,我原以为我们只需要对Solveds 求和,作者谈到了这一点,但目前尚不清楚Pending的情况如何起作用(例如修复@987654336 @确实对功能有不利影响,这可能是waysToMakeChange返回11的线索,或者该情况固定到的任何常量)。李> - 在
conquer、a和b中是Cents,而在divide中它们是ChangePuzzleArgs(又名([Cent], Cent))——这种转换发生在哪里?
注意:作为 SO 新手,我无法在原始答案下方评论,这可能更合适,但我希望这也是有用的。
【问题讨论】:
标签: haskell recursion functional-programming dynamic-programming recursion-schemes