我首先用下面的方法实现了欧几里得算法。
euclid x 0 = x
euclid x y = euclid y (x `mod` y)
该算法是尾递归的,我希望可以用recursion-schemes直观地编写它。然后,下面的 euc 是递归部分的摘录。这个 * 欧几里得 * 函数使用 euc,而 psi 用于一步处理。
euc :: (a -> Either t a) -> a -> t
euc psi = either id (euc psi) . psi
euclid :: Integral a => a -> a -> a
euclid x y = euc psi (x, y)
where psi (x, y) | m == 0 = Left y
| otherwise = Right (y, m)
where m = x `mod` y
- euc* 函数看起来像 apo 态射,但我不知道如何将 apo 专门化为 euc。在我看来,它们是完全不同的东西。是否可以将 euc 写为递归模式中的某种态射?
apo :: Functor f => (t -> f (Either (Fix f) t)) -> t -> Fix f
apo psi = In . fmap (uncurry either (id, apo psi)) . psi
问候。
3条答案
按热度按时间koaltpgm1#
我不知道你是否可以把它写成一个自同态,但我确实看到了一种你可以把它写成一个自同态的方法:
我还找到了一种将其写成Elgot代数的方法:
pwuypxnk2#
Either
在euc
和apo
中扮演不同的角色。您使用Left
来表示递归基本情况,而apo
使用Left
来表示协递归的提前终止(也就是说,添加一个额外的条件来中断展开)。但是,如果你想使用展开来表达你的算法,假设有足够的结构来展开,就不需要提前终止:psi
是Delayed
的余代数,ana psi
展开了一个Delayed
结构,其末端是GCD:为了得到最终的结果,我们必须消耗
Delayed
:假设我们正在执行一个
ana
,然后是一个cata
,我们最好切换到hylo
,它有效地组合了它们:在这一点上,我们可能会注意到
DelayedF
同构于Either
。因为对于我们目前的目的,我们只需要hylo
,而不是孤立的ana
或cata
,实际上可以用Either
替换DelayedF
,并完全跳过定义Delayed
(注意hylo
的类型没有提到隐含的递归数据结构,只有其对应的基函子):这样我们就得到了Joseph Sible's
hylo
solution,因为Either
是一个数据结构的基本函子,它以某种方式实现了递归算法。dzhpxtsq3#
我使用apomorphism提出了这个解决方案:使用@duplode中的Delayed结构可能会使这段代码更好。