是否存在投标分配?我需要什么功能?

问题描述 投票:6回答:2

我有代码(实际上是在C#中,但是这个问题与C#没有任何关系,所以我会谈到我在Haskell中说的所有类型)我在Either a b里面工作。然后我bind一个带有签名的函数,在Haskell中说是b -> (c, d),之后我想将c拉到外面并在左边的情况下默认它,即我想要(c, Either a d)。现在这种模式多次出现在我写的一个特定服务中,所以我提出了一种方法来实现它。然而,每当我在没有理解正确的理论基础的情况下“弥补”这样的方法时,它就会让我感到困扰。换句话说,我们在这里处理什么抽象?

我在一些F#代码中有类似的情况,我的对和我的任何一方都被颠倒了:(a, b) -> (b -> Either c d) -> Either c (a, d)。我问朋友这是什么,他让我转向traverse,这让我非常高兴,尽管由于缺乏类型类,我必须在F#中进行可怕的单态实现。 (我希望我可以将我在Visual Studio中的F1重新映射到Hackage;它是我编写.NET代码的主要资源之一)。但问题是遍历是:

class (Functor t, Foldable t) => Traversable t where
    traverse :: Applicative f => (a -> f b) -> t a -> f (t b)

这意味着当你开始使用一对并希望“绑定”其中任何一个时,它的效果很好,但是当你开始使用一个并且想要最终得到一对时它不起作用,因为pair不是Applicative

然而,我更多地考虑了我的第一个案例,那个不是traverse,并且意识到“在左边案例中默认c”只能通过映射左边的情况来完成,这会将问题改为具有这样的形状:Either (c, a) (c, d) -> (c, Either a d)我认识到我们在算术中用乘法和加法看到的模式:a(b + c) = ab + ac。我还记得布尔代数和集合理论中存在相同的模式(如果内存服务,A intersect (B union C) = (A intersect B) union (A intersect C))。显然,这里有一些抽象的代数结构。但是,内存不起作用,我不记得它被称为什么。维基百科上的一点点问题迅速解决了这个问题:这些是distributive法律。欢乐,哦,快乐,Kmett给了我们distribute

class Functor g => Distributive g where
    distribute :: Functor f => f (g a) -> g (f a)

它甚至有一个cotraverse,因为它是Travsersable的双重!可爱!!但是,我注意到没有(,)实例。哦,哦。因为,是的,“默认的c值”在哪里?然后我意识到,呃,我可能需要一些基于bifunctor的双向分配?也许对bitraversable来说是双重的?概念:

class Bifunctor g => Bidistributive g where
    bidistribute :: Bifunctor f => f (g a b) (g a c) -> g a (f b c)

这似乎是我所说的分配法的结构。我在Haskell中找不到这样的东西,因为我实际上在编写C#,这本身对我来说无关紧要。然而,对我来说重要的是不要提出虚假的抽象,并且尽可能地在我的代码中识别出合法的抽象,无论它们是否表达,都是为了我自己的理解。

我目前在我的C#代码中有一个.InsideOut(<default>)函数(扩展方法)(什么是黑客,对吧!)。我是否完全偏离基础来创建一个(是的,可悲的单形).Bidistribute(...)函数(扩展方法)来替换它并在调用它之前将左边的“默认”映射到左边的情况(或者只是识别“bidistributive” “从里到外”的性格)?

haskell math category-theory bifunctor distributive
2个回答
6
投票

bidistribute不能这样实施。考虑一些简单的例子

data Biconst c a b = Biconst c

instance Bifunctor (Biconst c) where
  bimap _ _ (Biconst c) = Biconst c

然后我们就有了专业化

bidistribute :: Biconst () (Void, ()) (Void, ()) -> (Void, Biconst () () ())
bidistribute (Biconst ()) = ( ????, Biconst () )

显然没有办法填补空白,需要有Void类型。

实际上,我认为你真的需要那里的Either(或者与它同构的东西),而不是任意的bifunctor。那么你的功能就是

uncozipL :: Functor f => Either (f a) (f b) -> f (Either a b)
uncozipL (Left l) = Left <$> l
uncozipL (Right r) = Right <$> l

它被定义为in adjunctions(找到using Hoogle)。


2
投票

根据@ leftaroundabout关于查看附录的提示,除了他在uncozipL中提到的his answer之外,如果我们推迟“默认左右两者中的第一个值”,我们也可以用unzipR来解决这个问题:

unzipR :: Functor u => u (a, b) -> (u a, u b)

然后,仍然需要映射对中的第一个元素,并用either (const "default") id之类的东西拉出值。有趣的是,如果你使用uncozipL,你需要知道其中一个是一对。如果你使用unzipR,你需要知道一个是其中之一。在这两种情况下,您都不使用抽象的bifunctor。

此外,我正在寻找的模式或抽象似乎是distributive lattice。维基百科说:

如果以下附加标识适用于L中的所有x,y和z,则格(L,∨,∧)是分布的:

x ∧ (y ∨ z) = (x ∧ y) ∨ (x ∧ z).

这正是我在许多不同地方发现的财产。

© www.soinside.com 2019 - 2024. All rights reserved.