我试图从这个关于递归方案的博客中理解组织同态。当我运行示例以解决博客中提到的变更问题时,我遇到了一个问题。
找零问题采用货币的面额,并试图找到创建给定金额所需的最小硬币数量。下面的代码取自博客,应该计算答案。
{-# LANGUAGE DeriveFunctor #-}
module Main where
import Control.Arrow ( (>>>) )
import Data.List ( partition )
import Prelude hiding (lookup)
newtype Term f = In {out :: f (Term f)}
data Attr f a = Attr
{ attribute :: a
, hole :: f (Attr f a)
}
type CVAlgebra f a = f (Attr f a) -> a
histo :: Functor f => CVAlgebra f a -> Term f -> a
histo h = out >>> fmap worker >>> h
where
worker t = Attr (histo h t) (fmap worker (out t))
type Cent = Int
coins :: [Cent]
coins = [50, 25, 10, 5, 1]
data Nat a
= Zero
| Next a
deriving (Functor)
-- Convert from a natural number to its foldable equivalent, and vice versa.
expand :: Int -> Term Nat
expand 0 = In Zero
expand n = In (Next (expand (n - 1)))
compress :: Nat (Attr Nat a) -> Int
compress Zero = 0
compress (Next (Attr _ x)) = 1 + compress x
change :: Cent -> Int
change amt = histo go (expand amt)
where
go :: Nat (Attr Nat Int) -> Int
go Zero = 1
go curr@(Next attr) =
let given = compress curr
validCoins = filter (<= given) coins
remaining = map (given -) validCoins
(zeroes, toProcess) = partition (== 0) remaining
results = sum (map (lookup attr) toProcess)
in length zeroes + results
lookup :: Attr Nat a -> Int -> a
lookup cache 0 = attribute cache
lookup cache n = lookup inner (n - 1) where (Next inner) = hole cache
现在,如果你评估change 10
它会给你 3。
这是...不正确的,因为您可以使用 1 枚价值 10 的硬币赚取 10。
所以我认为也许它正在解决硬币找零问题,它找到了你可以赚给定金额的最大方式。例如,您可以用{ 1, 1, ... 10 times }
, { 1, 1, 1, 1, 5}
, { 5, 5 }
, 4 种方式制作 10 { 10 }
。
那么这段代码有什么问题呢?解决问题的问题在哪里?
TLDR
此博客中关于递归方案的上述代码没有找到改变一笔钱的最小或最大方法。为什么它不起作用?