这种类似 monad 的函数式编程模式的名称是什么?
我偶尔会在代码中遇到类似于 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
嗯,它在某种意义上与 monad 密切相关,只是与
Monad
类型类不兼容。特别是,我们可以注意到以下相似之处:Monoid 具有关联操作,其标识定义在一致类型的值上:
mappend :: a ->一个-> a
和mempty :: a
。Monad 具有关联操作,其身份在类型构造函数上定义,例如:
join :: m (ma) -> m a
和return :: a -> m a
。函数(实际上是类别中的箭头)具有关联操作和标识,但关联操作由类别的对象索引,这里表示“类型”:
(.)::arr bc ->(.):: arr bc -> arr ab-> arr a c
和id :: arr a a
。...那么
join
按类型索引的 monad 会是什么?嗯。您可能会发现一些有趣的参考资料,探索相关概念:
post scriptum - 您在对该问题的评论中这样说:
实际上,将事情限制在
Applicative
变化中非常重要!a -> 之间的区别Marked p b
和Marked 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
andmempty :: a
.Monads have an associative operation with identity defined on type constructors, e.g.:
join :: m (m a) -> m a
andreturn :: 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
andid :: 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:
Actually, limiting things to
Applicative
changes matters significantly! The difference betweena -> Marked p b
andMarked p (a -> b)
is that, in the former, the properties of theMarked p
structure can depend on thea
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 typea
is isomorphic to a function of type() -> a
, you can probably turn it into some sort of two-tiered version ofArrow
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.