这种类似 monad 的函数式编程模式的名称是什么?

发布于 2024-11-30 12:11:52 字数 1144 浏览 0 评论 0原文

我偶尔会在代码中遇到类似于 monad 的模式,但是 不能在 >>= 之间保持一致的类型。

这是我能想到的最简单的例子:(

首先是一些类型级布尔值

data TyT = TyT
data TyF = TyF

class TyOr a b c | a b -> c

instance TyOr TyF TyF TyF
-- rest similarly

:)

现在这是我们的“monad”类型构造函数:

data Marked p a = Marked a
    deriving (Show)

对于给定的p标记的p 是一个 * -> * 其作用非常类似于 a 中的 m monad,但有所不同,正如接下来我们定义“bind”时所发生的那样:

(>>%) :: (TyOr p q r) => Marked p a -> (a -> Marked q b) -> Marked r b
(Marked x) >>% f = Marked y where Marked y = f x

这里的不同之处在于 >>% 的结果具有不同的类型 构造函数比参数。除此之外它基本上是一个单子。

我们可以这样使用它:(

a :: Marked TyF Int
a = Marked 5

f :: Int -> Marked TyT Int
f x = Marked (x + 1)

ghci> a >>% f
Marked 6

ghci> :t a >>% f
a >>% f :: Marked TyT Int

这是受到 outis 的观察的启发,Python 的“with”不能成为一个 monad 因为它改变了类型,但我已经以其他(更简单的)方式看到了它 也)。

I have occasionally encountered a pattern in code which resembles a monad but
does not keep a consistent type across >>=.

Here is the simplest example I could come up with:

(First some type-level booleans:

data TyT = TyT
data TyF = TyF

class TyOr a b c | a b -> c

instance TyOr TyF TyF TyF
-- rest similarly

)

Now here is our "monad" type constructor:

data Marked p a = Marked a
    deriving (Show)

For a given p, Marked p is a * -> * which acts very much like m in a
monad, but different, as occurs next, when we define "bind":

(>>%) :: (TyOr p q r) => Marked p a -> (a -> Marked q b) -> Marked r b
(Marked x) >>% f = Marked y where Marked y = f x

What's different here is that the result of >>% has a different type
constructor than the arguments. Other than that it's basically a monad.

We could use it like this:

a :: Marked TyF Int
a = Marked 5

f :: Int -> Marked TyT Int
f x = Marked (x + 1)

ghci> a >>% f
Marked 6

ghci> :t a >>% f
a >>% f :: Marked TyT Int

(This was inspired by outis's observation that Python's "with" can't be a
monad because it changes the type
, but I've seen it in other (simpler) ways
too).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

邮友 2024-12-07 12:11:52

嗯,它在某种意义上与 monad 密切相关,只是与 Monad 类型类不兼容。特别是,我们可以注意到以下相似之处:

  • Monoid 具有关联操作,其标识定义在一致类型的值上:mappend :: a ->一个-> amempty :: a

  • Monad 具有关联操作,其身份在类型构造函数上定义,例如:join :: m (ma) -> m areturn :: a -> m a

  • 函数(实际上是类别中的箭头)具有关联操作和标识,但关联操作由类别的对象索引,这里表示“类型”:(.)::arr bc ->(.):: arr bc -> arr ab-> arr a cid :: arr a a

...那么 join 按类型索引的 monad 会是什么?嗯。

您可能会发现一些有趣的参考资料,探索相关概念:


post scriptum - 您在对该问题的评论中这样说:

你是对的。我实际上想将其修复为更像 monad,尽管我并没有真正“使用”monad。我会编辑它。尽管我对 Applicatives 或多或少有同样的问题。

实际上,将事情限制在Applicative变化中非常重要! a -> 之间的区别Marked p bMarked p (a -> b) 的区别是,在前者中,Marked p 结构体的属性可以依赖于一个参数;而在后者中,标记独立于函数的参数。独立性意味着两者可以分开处理,这大大简化了事情;请注意,a 类型的任何值都与 () 类型的函数同构 -> a,您可能可以以简单的方式将其转换为某种两层版本的 Arrow

另一方面,涉及 Monad 意味着函数和标记上下文之间存在某种程度的交错,这使得事情变得复杂,原因类似于 在这个问题的答案中进行了讨论

Well, it's closely related to monads in some sense, just incompatible with the Monad type class. In particular, we can note the following parallels:

  • Monoids have an associative operation with identity defined on values of a consistent type: mappend :: a -> a -> a and mempty :: a.

  • Monads have an associative operation with identity defined on type constructors, e.g.: join :: m (m a) -> m a and return :: a -> m a.

  • Functions--really, arrows in a category--have an associative operation and identity, but the associative operation is indexed by the objects of the category, which here means "types": (.) :: arr b c -> arr a b -> arr a c and id :: arr a a.

...so what would a monad whose join is indexed by types be? Hm.

A few references you might find interesting, exploring related concepts:


post scriptum -- You said this in a comment on the question:

You're right. I actually want to fix that to be more monad-like though, even though I'm not really "using" monads. I'll edit it. Though I would have more or less the same question about Applicatives.

Actually, limiting things to Applicative changes matters significantly! The difference between a -> Marked p b and Marked p (a -> b) is that, in the former, the properties of the Marked p structure can depend on the a parameter; whereas in the latter, the marking is independent of the function's arguments. The independence means that the two can treated separately, which simplifies matters considerably; noting that any value of type a is isomorphic to a function of type () -> a, you can probably turn it into some sort of two-tiered version of Arrow in a straightforward manner.

On the other hand, involving Monad implies some degree of interleaving between the functions and the marking context, which complicates matters for reasons similar to those discussed in the answers to this question.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文