[英]What are the rules to compose f-algebras in a catamorphism
這里有一些簡單的F代數用於列表。 它們使用遞歸方案庫中的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-algebras的確切規則是什么?
“保持代數的結構”可以形式化為自然變換(可以在不同的算子之間)。
inList :: ListF a [a] -> [a]
inList Nil = []
inList (Cons a as) = a : as
ntDouble, ntTriple :: forall a. ListF Int a -> ListF Int a
algDouble = inList . ntDouble
algTriple = inList . ntTriple
然后,對於任何代數f
和自然變換n
,
cata (f . inList . n) = cata f . cata n
doubleAndTriple
示例是f = algTriple
和n = ntDouble
。
這並不容易推廣到更大類的代數。
我認為濾波器的情況更容易看到沒有類別,因為filter
是半群同態的事實: filter p . filter q = filter (liftA2 (&&) pq)
filter p . filter q = filter (liftA2 (&&) pq)
。
我在類似濾波器的代數上尋找一個通用但充分條件的“分配律”。 縮寫為afs = algFilterSmall
, afb = algFilterBig
。 我們向后推理,找到一個充分條件:
cata (afs . project . afb) = cata afs . cata afb -- Equation (0)
根據catamorphism的定義, z = cata (afs . project . afb)
是這個等式的唯一解(一個偽裝的交換圖):
z . inList = afs . project . afb . fmap z
用前一個等式的RHS代替z
:
cata afs . cata afb . inList = afs . project . afb . fmap (cata afs . cata afb)
-- (1), equivalent to (0)
在LHS上,我們將cata
的定義cata
為Haskell函數, cata afb = afb . fmap (cata afb) . project
cata afb = afb . fmap (cata afb) . project
cata afb = afb . fmap (cata afb) . project
,並簡化project . inList = id
project . inList = id
;
在RHS上,我們應用了一個fmap (f . g) = fmap f . fmap g
子法fmap (f . g) = fmap f . fmap g
fmap (f . g) = fmap f . fmap g
。
這會產生:
cata afs . afb . fmap (cata afb) = afs . project . afb . fmap (cata afs) . fmap (cata afb)
-- (2), equivalent to (1)
我們“縮小”最后一個因素fmap (cata afb)
(記住我們向后推理):
cata afs . afb = afs . project . afb . fmap (cata afs) -- (3), implies (2)
這是我能想到的最簡單的一個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.