如何将 Monad 实例定义为具有多个值的类型?

2023-11-27

我所说的多个值的意思是这样的:

data Foo a = Bar a | Baz a a

我想不出一个明确的方法来定义>>= for Baz:

instance Monad Foo where
    Bar x   >>= f = f x -- Great, that works perfectly!
    Baz x y >>= f = ??? -- What the heck do I even put here?

Perhaps:

frst (Bar a) = a
frst (Baz a a') = a

scnd (Bar a) = a
scnd (Baz a a') = a'

instance Monad Foo where
    return = Bar
    Bar x >>= f = f x
    Baz x y >>= f = Baz (frst (f x)) (scnd (f y))

这个定义的灵感来自于定义(>>=) for (Bool ->)。如果不清楚怎么办就问我。

让我们检查一下法律。这 ”return是单位”定律非常简单:

  return x >>= f
= Bar x >>= f
= f x

  m >>= return
= case m of
      Bar x -> return x
      Baz x y -> Baz (frst (return x)) (scnd (return y))
= case m of
      Bar x -> Bar x
      Baz x y -> Baz x y
= m

我相信我已经说服自己“(>>=)也是结合律”,但我确信这个证明对其他人来说是完全无法阅读的……我鼓励你尝试自己证明它,如果你遇到困难,可以将我的计算作为备忘单参考。

  m >>= (\v -> f v >>= g)
= case m of
      Bar x -> (\v -> f v >>= g) x
      Baz x y -> Baz (frst ((\v -> f v >>= g) x))
                     (scnd ((\v -> f v >>= g) y))
= case m of
      Bar x -> f x >>= g
      Baz x y -> Baz (frst (f x >>= g)) (scnd (f y >>= g))
= case m of
      Bar x -> case f x of
          Bar y -> g y
          Baz a b -> Baz (frst (g a)) (scnd (g b))
      Baz x y -> Baz (frst l) (scnd r) where
          l = case f x of
                  Bar a -> g a
                  Baz a b -> Baz (frst (g a)) (scnd (g b))
          r = case f y of
                  Bar a -> g a
                  Baz a b -> Baz (frst (g a)) (scnd (g b))
= case m of
      Bar x -> case f x of
          Bar y -> g y
          Baz a b -> Baz (frst (g a)) (scnd (g b))
      Baz x y -> Baz (frst (g (frst (f x))))
                     (scnd (g (scnd (f y))))
= case m of
      Bar a -> case f a of
          Bar x -> g x
          Baz x y -> Baz (frst (g x)) (scnd (g y))
      Baz a b -> case Baz (frst (f a)) (scnd (f b)) of
          Bar x -> g x
          Baz x y -> Baz (frst (g x)) (scnd (g y))
= case v of
      Bar x -> g x
      Baz x y -> Baz (frst (g x)) (scnd (g y))
  where v = case m of
                Bar a -> f a
                Baz a b -> Baz (frst (f a)) (scnd (f b))
= case m >>= f of
      Bar x -> g x
      Baz x y -> Baz (frst (g x)) (scnd (g y))
= (m >>= f) >>= g

edit好吧,我决定写一个简短的解释来解释这是如何受到启发的(Bool ->)尽管没有人问。所以,回想一下:

instance Monad (e ->) where
    m >>= f = \e -> f (m e) e

现在我们要定义

data Pair a = Pair a a

并观察到Bool -> a and Pair a非常相似:

to :: Pair a -> (Bool -> a)
to (Pair false true) = \bool -> case bool of
    False -> false
    True  -> true

from :: (Bool -> a) -> Pair a
from f = Pair (f False) (f True)

事实证明from and to是同构。换句话说:你可以交替地想到Bool -> a作为“二元容器”。好吧,如果我们尝试翻译会发生什么(e ->)实例为Monad进入Pair类型?这当然应该是可能的,因为它们是同构的。事实上,我们先从同构开始:

instance Monad Pair where
    return x = from (return x)
    m >>= f = from (to m >>= to . f)

现在我们可以“转动曲柄”:

  return x
= from (return x)
= from (\e -> x)
= Pair ((\e -> x) False) ((\e -> x) True)
= Pair x x

and:

  m@(Pair false true) >>= f
= from (to m >>= to . f)
= from (\e -> (to . f) (to m e) e)
= from (\e -> to (f (to m e)) e)
= Pair (g False) (g True) where
      g = \e -> to (f (to m e)) e
= Pair (to (f (to m False)) False) (to (f (to m True)) True)
= Pair (case f (to m False) of Pair false true -> false)
       (case f (to m True ) of Pair false true -> true )
= Pair (case f false of Pair false true -> false)
       (case f true  of Pair false true -> true )

所以我们现在可以重写实例而不依赖于(Bool ->)只需复制并粘贴上述计算的第一行和最后一行:

frstPair (Pair false true) = false
scndPair (Pair false true) = true

instance Monad Pair where
    return x = Pair x x
    Pair false true >>= f = Pair (frstPair (f false)) (scndPair (f true))

希望您能认识到这与定义有多么相似(>>=)我在上面给出了Foo.

edit 2另一个(不同的!)单子是可能的。从基类检查同构类型的行为:

type Foo = Product Identity Maybe

See 的文档Product。如果没有同构,则为:

instance Monad Foo where
    return x = Baz x x
    Bar x >>= f = Bar (frst (f x))
    Baz x y >>= f = case f y of
        Bar a -> Bar (frst (f x))
        Baz a b -> Baz (frst (f x)) b

从某种意义上说,当您添加更多单子操作时,我最初的提议“扩展”了结果的数量 - 从Bar in return并转换Bar不可撤销地Bazs 处于绑定状态 - 当您添加更多单子操作时,此实例会“收缩”可能的结果数量 - 从 a 开始Baz in return并转换Bazs to Bar不可挽回地陷入困境。如果你问我的话,这是一个非常有趣的设计选择!这也让我想知道是否还有另一个Monad实例为Product是可能的(可能对所涉及的函子有不同的约束)。

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

如何将 Monad 实例定义为具有多个值的类型? 的相关文章

  • Haskell:IORef 的性能

    我一直在尝试在 Haskell 中编码一个需要使用大量可变引用的算法 但与纯粹的惰性代码相比 它 也许并不奇怪 非常慢 考虑一个非常简单的例子 module Main where import Data IORef import Contr
  • Haskell - lambda 表达式

    我试图了解什么是有用的以及如何在 Haskell 中实际使用 lambda 表达式 我不太明白使用 lambda 表达式相对于定义函数的约定方式有何优势 例如 我通常会执行以下操作 let add x y x y 我可以简单地打电话 add
  • 在 monad 转换器类型类中使用列表 monad?

    我的目标是创建一个在 ReaderT WriterT 堆栈或 RWS 堆栈中使用列表 monad 的函数 更一般地说 如何在 mtl 类型类 例如 MonadReader MonadWriter 中使用列表 monad 我为什么要尝试这样做
  • Haskell:不在范围内:数据构造函数

    今天开始在学校学习 haskell 我遇到了函数问题 我不明白为什么它不在范围内 代码如下 ff Char gt Char gt Char ff A B x 0 y 1 x lt A y lt B x 1 y 0 和错误 md31 hs 2
  • 为什么在 where 子句中使用类型签名如此罕见?

    它是否有助于编译器优化 或者只是添加额外类型签名的多余工作 例如 人们经常看到 foo a gt b foo x bar x where bar x undefined 而不是 foo a gt b foo x bar x where ba
  • Haskell:需要了解 Functor 的签名

    有人能给我解释一下 Functor 的签名吗 Prelude gt info Functor class Functor f gt where fmap a gt b gt f a gt f b lt a gt f b gt f a 我不明
  • 如何同时将透镜(或任何其他光学器件)视为吸气剂和设置剂?

    我正在尝试编写一个通用记录更新程序 它允许人们轻松更新记录中的字段existing记录 字段形状相似incoming记录 这是我到目前为止所拥有的 applyUpdater fields existing incoming let gett
  • Haskell:对 Num 类型类的使用感到困惑

    我很困惑为什么这有效 f Num a gt a gt a f x x 42 但这并没有 g Num a gt a gt a g x x 4 2 我本来就明白Num包含实现运算符的所有类型 因此 如果42 is an Int and 4 2
  • 如何使用foldr为列表创建显示实例?

    我想为我的数据类型 我的列表 编写自己的显示实例 到目前为止 我的方法是有效的 但我总是在末尾有一个逗号 我已经尝试用最后一个元素启动折叠并将其从列表中删除 但它很麻烦而且不起作用 有没有更简单的方法来获得正确的解决方案 实际 1 2 3
  • Haskell Fibonacci 达到最大指定数?

    我有一个已启动并正在运行的 Haskell 函数 但它做错了事情 它应该输出最多指定最大数量的斐波那契数列 像这样 fibonacciSequence 86 1 1 2 3 5 8 13 21 33 54 我的代码当前输出斐波那契数列中的前
  • 如何只修改记录的一个字段而不完全重写它? [复制]

    这个问题在这里已经有答案了 It s the second time I m tackling this problem And for the second time this is while working with the Stat
  • 如何从具有函数依赖关系的类型类中获取和使用依赖类型?

    如何从具有函数依赖关系的类型类中获取和使用依赖类型 为了澄清并给出我最近的尝试的一个例子 从我正在编写的实际代码中最小化 class Identifiable a b a gt b where if you know a you know
  • 这是 unsafeCoerce 的安全使用吗?

    我遇到的情况是 我目前正在使用极其可怕的函数 unsafeCoerce 幸运的是 这并不是为了任何重要的事情 但我想知道这是否是该函数的安全使用 或者是否有其他方法可以解决其他人知道的这个特定问题 我的代码类似于以下内容 data Toke
  • 如何让 esqueleto 为我生成 SQL 字符串?

    我怎样才能让esqueleto从a生成一个SQL字符串from陈述 的文档toRawSql说 你可以打开持久的查询日志记录 我尝试了所有可能的形式MonadLogger我可以理解 但它从未打印任何 SQL 同一文档还说 手动使用此功能 是可
  • 使用默认值压缩而不是删除值?

    我正在 haskell 中寻找一个函数来压缩两个长度可能不同的列表 我能找到的所有 zip 函数都只是删除列表中比其他列表长的所有值 例如 在我的练习中 我有两个示例列表 如果第一个比第二个短 我必须用 0 填充 否则我必须使用 1 我不允
  • 这个实例有什么问题:ArrowApply Automaton?

    我希望 Automaton 有实例 ArrowApply 但 Control Arrow Transformer Automaton 没有 我认为下面的代码会表现良好 data Automaton b c Auto runAuto b gt
  • 如何与更高级别的类型合作

    玩弄教堂的数字 我遇到了无法指导 GHC 类型检查器处理高阶类型的情况 首先我写了一个版本 没有任何类型签名 module ChurchStripped where zero z z inc n z s s n z s natInteger
  • 来自数据类型的 Haskell 随机数

    我对 Haskell 还很陌生 我有一个数据类型 data Sentence Prop Int No Sentence And Sentence Or Sentence deriving Eq 我已经为它写了一个 Show 实例 然而 无论
  • Haskell 中的内部爆炸模式是否总是强制使用外部构造函数?

    在 Haskell 中 是否存在对于数据类型 LANGUAGE BangPatterns import Control DeepSeq data D D Int 实例 instance NFData D where rnf D 与具有另一个
  • Cabal:使用源代码构建目录

    我有一个src目录 在这个目录中我有Main hs文件和Test目录 在里面Test我有的目录Test hs模块 我需要用 cabal 来编译它 在我的阴谋集团文件中 我有 Executable main hs or lhs file co

随机推荐

  • C 和 C++ 中字符串文字连接的实现

    AFAIK 这个问题同样适用于C and C 中指定的 翻译阶段 的步骤 6C标准 C99 标准草案中的 5 1 1 2 规定相邻字符串文字必须连接成单个文字 I e printf helloworld c d Hello world n
  • Eclipse:在 Eclipse 中安装插件时出现错误,无法找到 jar 文件

    我正在关注以下网站http visualvm java net eclipse launcher html用于将 VisualVM 安装到 Eclipse Helios Version 3 6 中 为此 如上所述 我下载了 VisualVM
  • 如何使用捏缩放(UIPinchGestureRecognizer)来更改 UITextView 的宽度?

    我可以得到UIPinchGestureRecognizer处理程序来缩放对象 但我不想缩放 我想更改大小 例如我有一个UITextView我附上了一个UIPinchGestureRecognizer向它做手势 如果用户捏合我想更改文本视图的
  • 没有具有域权限的应用程序

    我正在尝试通过通用链接集成深度链接 一切都在开发者帐户上顺利解决 关联的域也在应用程序 ID 上启用 在服务器端 myapp com apple app site association 可用 但苹果搜索验证器总是抛出此错误 我不确定这到底
  • 错误:“const char [35]”和“const char [2]”类型的操作数对二进制“operator+”无效

    在我的文件顶部有 define AGE 42 稍后在文件中我多次使用 ID 包括一些看起来像这样的行 std string name Obama std string str Hello name you are AGE years old
  • 如何在SparkSQL中实现Like条件?

    如何编写 SQL 语句来达到目标 如下语句 SELECT FROM table t WHERE t a LIKE t b Thanks spark sql Column提供like方法 但目前 Spark 1 6 0 2 0 0 它仅适用于
  • 从文本文件中删除行?

    我有一个像这样的textfile txt First Line Second Line Third Line Fourth Line Fifth Line Sixth Line 如何去掉前三行和最后一行最舒服 with open textf
  • matplotlib 在 NaN 之后不继续行[重复]

    这个问题在这里已经有答案了 我有一个数组切片 array 1 0 2 0 3 0 None 4 0 None 5 0 None 6 0 None dtype object which when plotted looks like 如何让虚
  • 一种将 TD 置于 TR 中心的方法?

    我正在处理 HTML 电子邮件 并尝试将绿色 TD 放在白色 TR 中 以便在绿色框的左侧和右侧有 20 像素的白色边距 我尝试设置绿色部分的 TD 宽度并将边距设置为 0 auto 但绿色仅扩展到 TR 的宽度 尝试再放入 2 个 TD
  • 在 case 不起作用的情况下颤动多重

    是否可以根据多个文档 ID 获取价值 CollectionReference col1 Firestore instance collection service col1 where title isEqualTo Ac replacim
  • 支持向量机内核类型

    支持向量机中常用的核函数是线性 径向基函数和多项式 有人可以用简单的方式解释一下这个内核函数是什么吗 由于我是这个领域的新手 我不清楚这些内核类型的重要性是什么 让我们从头开始 支持向量机是一种线性模型 它总是寻找一个超平面来将一个类与另一
  • 如何使用SBT将一些文件复制到构建目标目录?

    如何复制一些源文件 例如 src main html html 到构建输出目录 例如 target scala 2 11 与 SBT 以便文件最终位于目标根并且不在classes子目录 如果我将源目录添加到 就会发生这种情况unmanage
  • 无法创建组件,因为它需要满足依赖关系

    我正在学习 DDD n Tier Repositories 等 有人向我推荐了 ASP NET Boilerplate 我决定使用它开始一个测试项目 我从未处理过依赖注入 所以这对我来说是全新的 但它使用 ius Castle Windso
  • Jquery next 找不到下一个 div?

    我有这个 HTML 结构 img width 25 height 25 src data apple logo jpg alt Chocolate
  • 在rails 4中重构大型routes.rb文件

    我正在将 Rails 3 应用程序升级到 Rails 4 0 1 在我的 Rails 3 应用程序中 我的目录中有以下代码application rb使用多个路由文件 config paths config routes Dir Rails
  • Mysql:将日期从“dd/mm/yyyy”转换为“yyyymmdd”

    我正在开发一个数据库 该数据库将日期存储在varchar 10 mysql 字段 太悲伤了 我无法更改数据库结构 我正在构建一个小插件 但我必须查询数据库 查找该数据字段在接下来的 10 天内的行 Example fid fdate 1 1
  • 基于应用程序变体的构建配置(BuildType + Flavor)

    我正在尝试设置signingConfig manifestPlaceholders buildConfigField对于应用程序变体 我可以为每个构建类型设置它们or ProductFlavor 独立 但我需要的是根据两个 ProductF
  • JS/jQuery 图像编辑器

    有没有人偶然发现用纯 JS 或 jQuery 完成的图像编辑器 就像 CKEditor 那样 我正在寻找一段代码 为图像添加句柄 以便您可以根据需要调整其大小 甚至拖动图像 谢谢 Edit 改写了 这是很棒的图像裁剪 调整大小 JQuery
  • 如何对Spark Structured Streaming进行单元测试?

    我想了解 Spark 结构化流的单元测试方面 我的场景是 我从 Kafka 获取数据 并使用 Spark 结构化流处理并在数据之上应用一些转换来使用它 我不确定如何使用 Scala 和 Spark 对此进行测试 有人可以告诉我如何使用 Sc
  • 如何将 Monad 实例定义为具有多个值的类型?

    我所说的多个值的意思是这样的 data Foo a Bar a Baz a a 我想不出一个明确的方法来定义 gt gt for Baz instance Monad Foo where Bar x gt gt f f x Great th