我在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(...)
函数(扩展方法)来替换它并在调用它之前将左案例的“默认”映射到左案例(或者只是识别“双向分配”字符“由内而外”)?