这里有一些针对列表的简单F-algebra。它们与recursion-schemes库中的cata
函数一起使用。
import Data.Functor.Foldable
algFilterSmall :: ListF Int [Int] -> [Int]
algFilterSmall Nil = []
algFilterSmall (Cons x xs) = if x >= 10 then (x:xs) else xs
algFilterBig :: ListF Int [Int] -> [Int]
algFilterBig Nil = []
algFilterBig (Cons x xs) = if x < 100 then (x:xs) else xs
algDouble :: ListF Int [Int] -> [Int]
algDouble Nil = []
algDouble (Cons x xs) = 2*x : xs
algTripple :: ListF Int [Int] -> [Int]
algTripple Nil = []
algTripple (Cons x xs) = 3*x : xs
现在我正在组合它们:
doubleAndTripple :: [Int] -> [Int]
doubleAndTripple = cata $ algTripple . project . algDouble
-- >>> doubleAndTripple [200,300,20,30,2,3]
-- [1200,1800,120,180,12,18]
doubleAndTriple
的功能正常。这两种代数结构都是“保持结构不变”的,它们不会改变列表的长度,因此 cata 可以将这两种代数结构应用于列表中的每个项目。
下一个是筛选和加倍:
filterAndDouble :: [Int] -> [Int]
filterAndDouble = cata $ algDouble . project . algFilterBig
-- >>> filterAndDouble [200,300,20,30,2,3]
-- [160,60,4,6]
它不能正常工作。我猜是因为algFilterBig
没有保持结构。
现在来看最后一个例子:
filterBoth :: [Int] -> [Int]
filterBoth = cata $ algFilterSmall . project . algFilterBig
-- >>> filterBoth [200,300,20,30,2,3]
-- [20,30]
这里的两个代数结构都不是结构保持的,但是这个例子是有效的。
组合f-代数的确切规则是什么?
inList
在库中被称为embed
(它是Corecursive
类的一个方法)。 - dfeuer