在变形中组成 f 代数的规则是什么
What are the rules to compose f-algebras in a catamorphism
这里有一些简单的列表 F 代数。他们使用来自 cata
的函数
recursion-schemes 图书馆。
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 代数的确切规则是什么?
"Structure preserving 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
是一个半群同态:filter p . filter q = filter (liftA2 (&&) p q)
.
我在 filter-like 代数上搜索 "distributive law" 的一般但充分条件。缩写一点afs = algFilterSmall
,afb = algFilterBig
。我们向后推理,找到一个充分条件:
cata (afs . project . afb) = cata afs . cata afb -- Equation (0)
根据变质的定义,z = cata (afs . project . afb)
是这个方程(伪装的交换图)的唯一解:
z . inList = afs . project . afb . fmap z
将z
代入上一个等式的RHS:
cata afs . cata afb . inList = afs . project . afb . fmap (cata afs . cata afb)
-- (1), equivalent to (0)
在 LHS 上,我们将 cata
的定义应用为 Haskell 函数,cata afb = afb . fmap (cata afb) . project
,并简化为 project . inList = id
;
在 RHS 上,我们应用函子定律 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)
我们"cosimplify"去掉最后一个因素fmap (cata afb)
(记住我们是倒推):
cata afs . afb = afs . project . afb . fmap (cata afs) -- (3), implies (2)
这是我能想到的最简单的一个。
这里有一些简单的列表 F 代数。他们使用来自 cata
的函数
recursion-schemes 图书馆。
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 代数的确切规则是什么?
"Structure preserving 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
是一个半群同态:filter p . filter q = filter (liftA2 (&&) p q)
.
我在 filter-like 代数上搜索 "distributive law" 的一般但充分条件。缩写一点afs = algFilterSmall
,afb = algFilterBig
。我们向后推理,找到一个充分条件:
cata (afs . project . afb) = cata afs . cata afb -- Equation (0)
根据变质的定义,z = cata (afs . project . afb)
是这个方程(伪装的交换图)的唯一解:
z . inList = afs . project . afb . fmap z
将z
代入上一个等式的RHS:
cata afs . cata afb . inList = afs . project . afb . fmap (cata afs . cata afb)
-- (1), equivalent to (0)
在 LHS 上,我们将
cata
的定义应用为 Haskell 函数,cata afb = afb . fmap (cata afb) . project
,并简化为project . inList = id
;在 RHS 上,我们应用函子定律
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)
我们"cosimplify"去掉最后一个因素fmap (cata afb)
(记住我们是倒推):
cata afs . afb = afs . project . afb . fmap (cata afs) -- (3), implies (2)
这是我能想到的最简单的一个。