7

我在Either a b. 然后,我bind使用 Haskell-speak 中带有签名的函数是b -> (c, d),之后我想将其拉到c外部并在左侧情况下默认它,即我想要(c, Either a d)。现在这种模式多次出现在我正在编写的一个特定服务中,所以我提出了一种方法来实现它。然而,每当我在不理解正确的理论基础的情况下“编造”这样的方法时,我都会感到困扰。换句话说,我们在这里处理的是什么抽象?

我在一些 F# 代码中遇到了类似的情况,其中我的对和我的任何一个都被颠倒了:(a, b) -> (b -> Either c d) -> Either c (a, d). 我问一个朋友这是什么,他让我开始遍历,这让我非常高兴,尽管由于缺少类型类,我不得不在 F# 中进行可怕的单态实现。(我希望我可以F1在 Visual Studio 中重新映射到 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))。显然这里有一些抽象的代数结构。然而,记忆不起作用,我不记得它叫什么了。在 Wikipedia 上浏览一下很快就解决了这个问题:这些是分配法则。快乐,哦,快乐,Kmett 给了我们分发

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

它甚至有一个cotraverse,因为它是双重的Travsersable!迷人的!!但是,我注意到没有(,)实例。哦哦。因为,是的,“默认c值”在哪里出现?然后我意识到,哦,我可能需要基于双函子的双向分配器之类的东西?也许双重到可比特遍历?从概念上讲:

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

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

我目前.InsideOut(<default>)在我的 C# 代码中有一个函数(扩展方法)(真是个 hack,对!)。我会完全偏离基础来创建一个(是的,可悲的是单态).Bidistribute(...)函数(扩展方法)来替换它并在调用它之前将左案例的“默认”映射到左案例(或者只是识别“双向分配”字符“由内而外”)?

4

2 回答 2

7

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 () )

显然没有办法填补空白,这需要有 type Void

实际上,我认为您确实需要Either那里(或与之同构的东西)而不是任意的双函子。那么你的功能就是

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

adjunctions使用 Hoogle找到)中定义。

于 2017-12-22T17:33:42.450 回答
3

基于@leftaroundabout 的提示来查看附加词,除了他在回答uncozipL中提到的之外,如果我们推迟“在任何一个的左侧情况下默认该对的第一个值”,我们还可以通过以下方式解决这个问题:unzipR

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

然后仍然需要映射该对中的第一个元素并使用类似either (const "default") id. 有趣的是,如果您使用uncozipL,您需要知道其中一个是一对。如果您使用unzipR,您需要知道其中一个是两者之一。在这两种情况下,您都不使用抽象双函子。

此外,我正在寻找的模式或抽象似乎是一个分布格。维基百科说:

如果以下附加恒等式对 L 中的所有 x、y 和 z 成立,则格 (L,∨,∧) 是可分配的:

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

这正是我在许多不同地方观察到的特性。

于 2017-12-23T00:45:30.853 回答