在一个变形中组成f-代数的规则是什么

时间:2018-02-17 17:29:45

标签: haskell recursion-schemes

以下是列表的一些简单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-algebras的确切规则是什么?

1 个答案:

答案 0 :(得分:4)

&#34;结构保留代数&#34;可以形式化为自然变换(可以在不同的仿函数之间)。

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 = algTriplen = ntDouble的示例。

这并不容易推广到更大类的代数。

我认为过滤器的情况更容易看到没有类别,因为filter是一个半群同态:filter p . filter q = filter (liftA2 (&&) p q)

我搜索了一个通用但足够的条件来制定分配法律#34;在类似滤波器的代数上。缩写afs = algFilterSmallafb = 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的定义应用为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)

我们&#34; cosimplify&#34;离开最后一个因素fmap (cata afb)(记住我们向后推理):

cata afs . afb = afs . project . afb . fmap (cata afs)  -- (3), implies (2)

这是我能想到的最简单的一个。