每个替代 Monad 都可以过滤吗?

2024-02-15

集合的范畴包括笛卡尔幺半群和柯笛卡尔幺半群。下面列出了这两种幺半群结构的规范同构类型:

type x + y = Either x y
type x × y = (x, y)

data Iso a b = Iso { fwd :: a -> b, bwd :: b -> a }

eassoc :: Iso ((x + y) + z) (x + (y + z))
elunit :: Iso (Void + x) x
erunit :: Iso (x + Void) x

tassoc :: Iso ((x × y) × z) (x × (y × z))
tlunit :: Iso (() × x) x
trunit :: Iso (x × ()) x

为了这个问题的目的,我定义Alternative成为 Hask 下的松散幺半群函子Either张量到 Hask 下(,)张量(仅此而已):

class Functor f => Alt f
  where
  union :: f a × f b -> f (a + b)

class Alt f => Alternative f
  where
  nil :: () -> f Void

这些定律只是针对松散幺半群函子的定律。

关联性:

fwd tassoc >>> bimap id union >>> union
=
bimap union id >>> union >>> fmap (fwd eassoc)

左单元:

fwd tlunit
=
bimap nil id >>> union >>> fmap (fwd elunit)

右单位:

fwd trunit
=
bimap id nil >>> union >>> fmap (fwd erunit)

以下是如何恢复更熟悉的操作Alternative根据松散幺半群函子编码的一致性映射的类型类:

(<|>) :: Alt f => f a -> f a -> f a
x <|> y = either id id <$> union (Left <$> x, Right <$> y)

empty :: Alternative f => f a
empty = absurd <$> nil ()

我定义Filterable函子是oplaxHask 下的幺半群函子Either张量到 Hask 下(,) tensor:

class Functor f => Filter f
  where
  partition :: f (a + b) -> f a × f b

class Filter f => Filterable f
  where
  trivial :: f Void -> ()
  trivial = const ()

其定律只是向后宽松的幺半群函子定律:

关联性:

bwd tassoc <<< bimap id partition <<< partition
=
bimap partition id <<< partition <<< fmap (bwd eassoc)

左单元:

bwd tlunit
=
bimap trivial id <<< partition <<< fmap (bwd elunit)

右单位:

bwd trunit
=
bimap id trivial <<< partition <<< fmap (bwd erunit)

定义标准过滤器函数,例如mapMaybe and filter就 oplax 幺半群函子编码而言,留给感兴趣的读者作为练习:

mapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
mapMaybe = _

filter :: Filterable f => (a -> Bool) -> f a -> f a
filter = _

问题是这样的:是每一个Alternative Monad also Filterable?

我们可以输入俄罗斯方块来实现:

instance (Alternative f, Monad f) => Filter f
  where
  partition fab = (fab >>= either return (const empty), fab >>= either (const empty) return)

但这种实施总是合法的吗?有时合法吗(对于“有时”的某些正式定义)?证明、反例和/或非正式论证都非常有用。谢谢。


这是一个广泛支持你美好想法的论点。

第一部分:mapMaybe

我的计划是重申这个问题mapMaybe,希望这样做能让我们进入更熟悉的领域。为此,我将使用一些Either-杂耍实用功能:

maybeToRight :: a -> Maybe b -> Either a b
rightToMaybe :: Either a b -> Maybe b
leftToMaybe :: Either a b -> Maybe a
flipEither :: Either a b -> Either b a

(我取了前三个名字relude https://hackage.haskell.org/package/relude-0.6.0.0/docs/Relude-Monad-Either.html,第四个来自errors https://hackage.haskell.org/package/errors-2.3.0/docs/Data-EitherR.html#v:flipEither。顺便一提,errors offers maybeToRight and rightToMaybe as note and hush分别在Control.Error.Util https://hackage.haskell.org/package/errors-2.3.0/docs/Control-Error-Util.html.)

正如你所指出的,mapMaybe可以定义为partition:

mapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
mapMaybe f = snd . partition . fmap (maybeToRight () . f)

至关重要的是,我们也可以反过来:

partition :: Filterable f => f (Either a b) -> (f a, f b)
partition = mapMaybe leftToMaybe &&& mapMaybe rightToMaybe

这表明根据以下方面重新制定法律是有意义的mapMaybe。有了身份法,这样做给了我们一个很好的借口来完全忘记trivial:

-- Left and right unit
mapMaybe rightToMaybe . fmap (bwd elunit) = id  -- [I]
mapMaybe leftToMaybe . fmap (bwd erunit) = id   -- [II]

至于关联性,我们可以使用rightToMaybe and leftToMaybe将定律分解为三个方程,每个方程对应我们从连续划分中得到的每个分量:

-- Associativity
mapMaybe rightToMaybe . fmap (bwd eassoc)
    = mapMaybe rightToMaybe . mapMaybe rightToMaybe  -- [III]
mapMaybe rightToMaybe . mapMaybe leftToMaybe . fmap (bwd eassoc)
    = mapMaybe leftToMaybe . mapMaybe rightToMaybe   -- [IV]
mapMaybe leftToMaybe . fmap (bwd eassoc)
    = mapMaybe leftToMaybe . mapMaybe leftToMaybe    -- [V]

参数化意味着mapMaybe是不可知论的Either我们在这里处理的价值观。既然如此,我们可以使用我们的小武器库Either同构来打乱事物并表明 [I] 等价于 [II],而 [III] 等价于 [V]。我们现在只剩下三个方程:

mapMaybe rightToMaybe . fmap (bwd elunit) = id       -- [I]
mapMaybe rightToMaybe . fmap (bwd eassoc)
    = mapMaybe rightToMaybe . mapMaybe rightToMaybe  -- [III]
mapMaybe rightToMaybe . mapMaybe leftToMaybe . fmap (bwd eassoc)
    = mapMaybe leftToMaybe . mapMaybe rightToMaybe   -- [IV]

参数化让我们能够吞下fmap in [I]:

mapMaybe (rightToMaybe . bwd elunit) = id

然而,这根本就是……

mapMaybe Just = id

...这相当于守恒定律/恒等律枯萎的's Filterable https://hackage.haskell.org/package/witherable-class-0/docs/Data-Witherable-Class.html:

mapMaybe (Just . f) = fmap f

That Filterable还有一个组合律:

-- The (<=<) is from the Maybe monad.
mapMaybe g . mapMaybe f = mapMaybe (g <=< f)

我们是否也可以从我们的法律中推导出这一点?让我们从[III]开始,再次让参数化发挥作用。这个比较棘手,所以我将其完整写下来:

mapMaybe rightToMaybe . fmap (bwd eassoc)
    = mapMaybe rightToMaybe . mapMaybe rightToMaybe  -- [III]

-- f :: a -> Maybe b; g :: b -> Maybe c
-- Precomposing fmap (right (maybeToRight () . g) . maybeToRight () . f)
-- on both sides:
mapMaybe rightToMaybe . fmap (bwd eassoc)
  . fmap (right (maybeToRight () . g) . maybeToRight () . f)
    = mapMaybe rightToMaybe . mapMaybe rightToMaybe 
      . fmap (right (maybeToRight () . g) . maybeToRight () . f)

mapMaybe rightToMaybe . mapMaybe rightToMaybe 
  . fmap (right (maybeToRight () . g) . maybeToRight () . f)  -- RHS
mapMaybe rightToMaybe . fmap (maybeToRight () . g)
  . mapMaybe rightToMaybe . fmap (maybeToRight () . f)
mapMaybe (rightToMaybe . maybeToRight () . g)
 . mapMaybe (rightToMaybe . maybeToRight () . f)
mapMaybe g . mapMaybe f

mapMaybe rightToMaybe . fmap (bwd eassoc)
  . fmap (right (maybeToRight () . g) . maybeToRight () . f)  -- LHS
mapMaybe (rightToMaybe . bwd eassoc 
    . right (maybeToRight () . g) . maybeToRight () . f)
mapMaybe (rightToMaybe . bwd eassoc 
    . right (maybeToRight ()) . maybeToRight () . fmap @Maybe g . f)
-- join @Maybe
--     = rightToMaybe . bwd eassoc . right (maybeToRight ()) . maybeToRight ()
mapMaybe (join @Maybe . fmap @Maybe g . f)
mapMaybe (g <=< f)  -- mapMaybe (g <=< f) = mapMaybe g . mapMaybe f

在另一个方向:

mapMaybe (g <=< f) = mapMaybe g . mapMaybe f
-- f = rightToMaybe; g = rightToMaybe
mapMaybe (rightToMaybe <=< rightToMaybe)
    = mapMaybe rightToMaybe . mapMaybe rightToMaybe
mapMaybe (rightToMaybe <=< rightToMaybe)  -- LHS
mapMaybe (join @Maybe . fmap @Maybe rightToMaybe . rightToMaybe)
-- join @Maybe
--     = rightToMaybe . bwd eassoc . right (maybeToRight ()) . maybeToRight ()
mapMaybe (rightToMaybe . bwd eassoc 
    . right (maybeToRight ()) . maybeToRight ()
      . fmap @Maybe rightToMaybe . rightToMaybe)
mapMaybe (rightToMaybe . bwd eassoc 
    . right (maybeToRight () . rightToMaybe) 
      . maybeToRight () . rightToMaybe)
mapMaybe (rightToMaybe . bwd eassoc)  -- See note below.
mapMaybe rightToMaybe . fmap (bwd eassoc)
-- mapMaybe rightToMaybe . fmap (bwd eassoc)
--     = mapMaybe rightToMaybe . mapMaybe rightToMaybe

(注:虽然maybeToRight () . rightToMaybe :: Either a b -> Either () b is not id,在上面的推导中,无论如何,左值都会被丢弃,因此将其删除是公平的,就好像它是一样id.)

因此[III]等价于复合律枯萎的's Filterable.

此时,我们可以用组合律来处理[IV]:

mapMaybe rightToMaybe . mapMaybe leftToMaybe . fmap (bwd eassoc)
    = mapMaybe leftToMaybe . mapMaybe rightToMaybe   -- [IV]
mapMaybe (rightToMaybe <=< leftToMaybe) . fmap (bwd eassoc)
    = mapMaybe (letfToMaybe <=< rightToMaybe)
mapMaybe (rightToMaybe <=< leftToMaybe . bwd eassoc)
    = mapMaybe (letfToMaybe <=< rightToMaybe)
-- Sufficient condition:
rightToMaybe <=< leftToMaybe . bwd eassoc = letfToMaybe <=< rightToMaybe
-- The condition holds, as can be directly verified by substiuting the definitions.

这足以表明你的课程达到了一个完善的公式Filterable,这是一个非常好的结果。以下是法律的回顾:

mapMaybe Just = id                            -- Identity
mapMaybe g . mapMaybe f = mapMaybe (g <=< f)  -- Composition

As the 枯萎的文档注释,这些是函子的函子定律克莱斯利也许 to Hask.

第二部分:Alternative 和 Monad

现在我们可以解决您的实际问题,即关于替代单子的问题。您提议的实施partition was:

partitionAM :: (Alternative f, Monad f) => f (Either a b) -> (f a, f b)
partitionAM
    = (either return (const empty) =<<) &&& (either (const empty) return =<<)

按照我的更广泛的计划,我将转向mapMaybe推介会:

mapMaybe f
snd . partition . fmap (maybeToRight () . f)
snd . (either return (const empty) =<<) &&& (either (const empty) return =<<)
    . fmap (maybeToRight () . f)
(either (const empty) return =<<) . fmap (maybeToRight () . f)
(either (const empty) return . maybeToRight . f =<<)
(maybe empty return . f =<<)

所以我们可以定义:

mapMaybeAM :: (Alternative f, Monad f) => (a -> Maybe b) -> f a -> f b
mapMaybeAM f u = maybe empty return . f =<< u

或者,用无点拼写:

mapMaybeAM = (=<<) . (maybe empty return .)

上面几段我注意到Filterable法律规定mapMaybe是函子的态射映射克莱斯利也许 to Hask。由于函子的复合是一个函子,并且(=<<)是函子的态射映射克莱斯利夫 to Hask, (maybe empty return .)是函子的态射映射克莱斯利也许 to 克莱斯利夫足以mapMaybeAM是合法的。相关函子定律是:

maybe empty return . Just = return  -- Identity
maybe empty return . g <=< maybe empty return . f
    = maybe empty return . (g <=< f)  -- Composition

该恒等定律成立,所以让我们关注组合定律:

maybe empty return . g <=< maybe empty return . f
    = maybe empty return . (g <=< f)
maybe empty return . g =<< maybe empty return (f a)
    = maybe empty return (g =<< f a)
-- Case 1: f a = Nothing
maybe empty return . g =<< maybe empty return Nothing
    = maybe empty return (g =<< Nothing)
maybe empty return . g =<< empty = maybe empty return Nothing
maybe empty return . g =<< empty = empty  -- To be continued.
-- Case 2: f a = Just b
maybe empty return . g =<< maybe empty return (Just b)
    = maybe empty return (g =<< Just b)
maybe empty return . g =<< return b = maybe empty return (g b)
maybe empty return (g b) = maybe empty return (g b)  -- OK.

所以,mapMaybeAM是合法的,当且仅当maybe empty return . g =<< empty = empty对于任何g。现在,如果empty定义为absurd <$> nil (),正如您在这里所做的那样,我们可以证明f =<< empty = empty对于任何f:

f =<< empty = empty
f =<< empty  -- LHS
f =<< absurd <$> nil ()
f . absurd =<< nil ()
-- By parametricity, f . absurd = absurd, for any f.
absurd =<< nil ()
return . absurd =<< nil ()
absurd <$> nil ()
empty  -- LHS = RHS

直观地讲,如果empty确实是空的(考虑到我们在这里使用的定义,它一定是空的),因此不会有任何值f应用于,等等f =<< empty不会产生任何结果,除了empty.

这里的另一种方法是研究Alternative and Monad类。碰巧,有一个替代 monad 的类:MonadPlus https://downloads.haskell.org/ghc/8.8.3/docs/html/libraries/base-4.13.0.0/Control-Monad.html#t:MonadPlus。据此,重新设计了mapMaybe可能看起来像这样:

-- Lawful iff, for any f, mzero >>= maybe empty mzero . f = mzero
mmapMaybe :: MonadPlus m => (a -> Maybe b) -> m a -> m b
mmapMaybe f m = m >>= maybe mzero return . f

虽然有不同意见 https://en.wikibooks.org/wiki/Haskell/Alternative_and_MonadPlus#Other_suggested_laws哪一套法律最适合MonadPlus,似乎没有人反对的法律之一是……

mzero >>= f = mzero  -- Left zero

...这正是empty我们在上面讨论了几段。的合法性mmapMaybe紧接着左零定律。

(顺便,Control.Monad提供mfilter :: MonadPlus m => (a -> Bool) -> m a -> m a https://downloads.haskell.org/ghc/8.8.3/docs/html/libraries/base-4.13.0.0/Control-Monad.html#v:mfilter,它匹配filter我们可以定义使用mmapMaybe.)

总之:

但这种实施总是合法的吗?有时合法吗(对于“有时”的某些正式定义)?

是的,实施是合法的。这个结论取决于empty确实是空的,因为它应该是空的,或者在左零之后的相关替代单子上MonadPlus法,归结起来几乎是同一件事。

值得强调的是Filterable不包含在MonadPlus,我们可以通过以下反例来说明:

  • ZipList:可过滤,但不是单子。这Filterable实例与列表的实例相同,尽管Alternative一个是不同的。

  • Map:可过滤,但既不是单子也不是应用程序。实际上,Map甚至无法应用,因为没有合理的实施pure。然而它确实有自己的empty.

  • MaybeT f: 虽然其Monad and Alternative实例需要f成为一个单子,并且是一个孤立的empty定义至少需要Applicative, the Filterable实例只需要Functor f(如果你滑倒任何东西都变得可以过滤Maybe层到其中)。

第三部分:空

说到这里,人们可能仍然想知道它的作用有多大。empty, or nil,真正发挥作用的是Filterable。它不是一个类方法,但大多数实例似乎都有一个合理的版本。

我们可以确定的一件事是,如果可过滤类型有任何居民,那么至少其中一个将是一个空结构,因为我们总是可以取出任何居民并过滤掉所有内容:

chop :: Filterable f => f a -> f Void
chop = mapMaybe (const Nothing)

的存在chop,虽然并不意味着会有single nil空值,或者chop总是会给出相同的结果。例如,考虑一下,MaybeT IO, whose Filterable实例可能被认为是审查结果的一种方式IO计算。该实例是完全合法的,尽管chop可以产生不同的MaybeT IO Void带有任意值的值IO影响。

最后一点,你有提到 https://stackoverflow.com/questions/60732274/is-every-alternative-monad-filterable/60796049#comment107679715_60796049使用强幺半群函子的可能性,以便Alternative and Filterable通过制作链接union/partition and nil/trivial同构。拥有union and partition因为互逆是可以想象的,但相当有限,因为union . partition丢弃有关大部分实例的元素排列的一些信息。至于另一个同构,trivial . nil是微不足道的,但是nil . trivial有趣的是它意味着只有一个f Void价值,占有相当大份额的东西Filterable实例。碰巧有一个MonadPlus此条件的版本。如果我们要求的话,对于任何u...

absurd <$> chop u = mzero

...然后替换mmapMaybe从第二部分,我们得到:

absurd <$> chop u = mzero
absurd <$> mmapMaybe (const Nothing) u = mzero
mmapMaybe (fmap absurd . const Nothing) u = mzero
mmapMaybe (const Nothing) u = mzero
u >>= maybe mzero return . const Nothing = mzero
u >>= const mzero = mzero
u >> mzero = mzero

这个性质被称为右零定律MonadPlus, 尽管有充分的理由质疑其作为法律的地位 https://winterkoninkje.dreamwidth.org/90905.html属于那个特定的班级。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

每个替代 Monad 都可以过滤吗? 的相关文章

随机推荐

  • 更新连接视图而不出现非密钥保留错误

    我在 Oracle 11g 数据库中创建了一个视图 该视图由两个连接表组成 如下所示 CREATE FORCE VIEW my dataview key1 key2 column from table1 column from table2
  • IIS:如何从命令行取消部署/删除/删除 Web 应用程序?

    假设本地 IIS 服务器上部署了一个 Web 应用程序 当我需要删除 取消部署它时 我可以转到 IIS 管理器 右键单击该应用程序 然后选择 删除应用程序和内容 等等 但是 我需要从命令行执行相同的操作 如何执行 可以假设应用程序的名称是已
  • 如何获取 PostgreSQL 中特定模式的数据库中存储的所有函数的列表?

    我希望能够连接到 PostgreSQL 数据库并找到特定模式的所有函数 我的想法是 我可以对 pg catalog 或 information schema 进行一些查询并获取所有函数的列表 但我无法弄清楚名称和参数的存储位置 我正在寻找一
  • 如何使用 JSCH 连接到 SSH 服务器?

    我正在尝试使用 jsch 连接到我的开放 ssh ubuntu 服务器 我只是想看看是否可以使用 SSH 从 Android 手机连接到 Linux 服务器 但它不起作用 当我在 Android 手机上启动应用程序时 应用程序崩溃了 我已附
  • 如何更改 zend 框架布局中的元标记

    所以我在layout phtml上设置了一些默认元标记 this gt headTitle and this gt headMeta gt appendName 并在layout phtml的标头处得到回显 我的问题是 如何更改视图文件中的
  • SQL Server 2008 中的 USING 关键字是什么?

    我知道 SQL 子句 USING 的美妙用法 它类似于 NATURAL JOIN 但您必须详细说明连接列 您可以更简单 更快 地连接具有相同键和外键的表 并且查询的输出不包含冗余字段 然而 SQL Server 2008 不支持使用 USI
  • Tab 键在 IWebbrowser2 中不起作用

    我正在使用 ActiveX 控件在 ATL 应用程序 IWebbrowser2 中实现嵌入式浏览器 问题是 我无法使用 Tab 键在文本字段之间跳转 按 T ab 键什么也不做 按 Enter 键将按预期提交表单 问题存在 例如在 Face
  • 选择 XML 中的节点

    我正在尝试在 c 中使用 xpath 选择节点 这是我的 XML 文件
  • Struts2注释验证拦截器

    我在将 struts2 jquery plugin 3 6 0 实现到 Struts2 2 3 14 3 网站中时遇到了令人沮丧的时间 我最近将Struts2版本更新到2 3 14 3及其所有依赖项 并且网站功能完全正常 我现在正在尝试更新
  • 如何获取当前运行的实际窗口的标题?

    我有一个问题 我只需要获取列表中所有窗口的标题 我所说的标题是指 记事本 总指挥官 只是窗口顶部边缘显示的文本 到目前为止我已经到了这里 function EnumWindowProc hHwnd HWND lParam integer b
  • 统计机器翻译的短语提取算法

    我用 SMT 的短语提取算法编写了以下代码 GitHub https github com alvations nltk blob develop nltk align phrase based py coding utf 8 def ph
  • 如何从 Scala-Play 应用程序中的 URL 中提取路由变量的值?

    我正在为 Play 框架编写一个模块 在我的模块的一部分中 我有以下代码 abstract class SecurityFiltering extends GlobalSettings override def onRequestRecei
  • iOS画屏视频采集不流畅

    我正在创建一个应用程序 我们可以在 imageView 中使用手指进行绘图 同时我们也可以记录屏幕 到目前为止我已经完成了这些功能 但问题是一旦视频录制完成 如果我们播放录制的视频 手指在视频中绘图不流畅 我没有使用 opengl 绘图在
  • HTML5 画布和线宽

    我正在画布上绘制折线图 线条画得很好 图表是按比例缩放的 每个部分都被绘制 颜色都可以等等 我唯一的问题是视觉上线宽有所不同 它几乎就像书法笔的笔尖 如果笔画向上 则线条较细 如果笔画水平 则线条较粗 我的线条粗细是恒定的 并且我的stro
  • FCM getToken() 不返回任何内容

    我正在尝试将 Firebase Cloud Messaging 与 Angular2 结合使用 但他们似乎不希望我们这样做 Google 我一直在关注this https firebase google com docs cloud mes
  • iis7 asp.net mvc webapi 重写

    我遇到了与参考帖子中相同的问题 由于 ExtensionlessUrlHandler WebAPI 重写规则失败 https stackoverflow com questions 13885343 rewrite rule for web
  • 在 .NET 程序中将图像加载/创建到 SharpDX 中

    我正在尝试使用 SharpDX 使用 DirectX 创建一个简单的类似迷宫的 2D 程序 为此 我想创建可以在屏幕上渲染墙壁 走廊 迷宫外部等的位图 但是 我似乎不知道如何将现有图像文件加载到 Bitmap 类中SharpDX http
  • Google Page Speed-like 图像优化 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我的网站有大约 2 万张产品图片 Google Page Speed 告诉我它们可以优化 这是正确的
  • 在 R 中使用 git2r::clone 进行 SSH 身份验证时获取“不支持的 URL 协议”

    我正在尝试使用 git2r clone 克隆私人存储库via SSH 不是 HTTPS 协议 在 R 中通过执行 git2r clone email protected cdn cgi l email protection team nam
  • 每个替代 Monad 都可以过滤吗?

    集合的范畴包括笛卡尔幺半群和柯笛卡尔幺半群 下面列出了这两种幺半群结构的规范同构类型 type x y Either x y type x y x y data Iso a b Iso fwd a gt b bwd b gt a easso