[英]Good examples of Not a Functor/Functor/Applicative/Monad?
While explaining to someone what a type class X is I struggle to find good examples of data structures which are exactly X.在向某人解释什么是类型类 X 时,我很难找到恰好是 X 的数据结构的好例子。
So, I request examples for:因此,我请求以下示例:
I think there are plenty examples of Monad everywhere, but a good example of Monad with some relation to previous examples could complete the picture.我认为到处都有很多 Monad 的例子,但是一个很好的 Monad 例子与之前的例子有一些关系可以完成这幅画。
I look for examples which would be similar to each other, differing only in aspects important for belonging to the particular type class.我寻找彼此相似的示例,仅在对属于特定类型类的重要方面有所不同。
If one could manage to sneak up an example of Arrow somewhere in this hierarchy (is it between Applicative and Monad?), that would be great too!如果有人可以设法在这个层次结构中的某个地方偷偷摸摸一个 Arrow 的例子(它是在 Applicative 和 Monad 之间吗?),那也太棒了!
A type constructor which is not a Functor:不是 Functor 的类型构造函数:
newtype T a = T (a -> Int)
You can make a contravariant functor out of it, but not a (covariant) functor.你可以用它制作一个逆变函子,但不能制作一个(协变)函子。 Try writing
fmap
and you'll fail.尝试编写
fmap
并且你会失败。 Note that the contravariant functor version is reversed:请注意,逆变函子版本是相反的:
fmap :: Functor f => (a -> b) -> f a -> f b
contramap :: Contravariant f => (a -> b) -> f b -> f a
A type constructor which is a functor, but not Applicative:一个类型构造函数,它是一个函子,但不是 Applicative:
I don't have a good example.我没有很好的例子。 There is
Const
, but ideally I'd like a concrete non-Monoid and I can't think of any.有
Const
,但理想情况下我想要一个具体的非 Monoid 并且我想不出任何。 All types are basically numeric, enumerations, products, sums, or functions when you get down to it.所有类型基本上都是数字、枚举、乘积、总和或函数。 You can see below pigworker and I disagreeing about whether
Data.Void
is a Monoid
;你可以在 pigworker 下面看到我不同意
Data.Void
是否是Monoid
;
instance Monoid Data.Void where
mempty = undefined
mappend _ _ = undefined
mconcat _ = undefined
Since _|_
is a legal value in Haskell, and in fact the only legal value of Data.Void
, this meets the Monoid rules.由于
_|_
在 Haskell 中是合法值,并且实际上是Data.Void
的唯一合法值, Data.Void
这符合 Monoid 规则。 I am unsure what unsafeCoerce
has to do with it, because your program is no longer guaranteed not to violate Haskell semantics as soon as you use any unsafe
function.我不确定
unsafeCoerce
与它有什么关系,因为一旦您使用任何unsafe
函数,您的程序就不再保证不会违反 Haskell 语义。
See the Haskell Wiki for an article on bottom ( link ) or unsafe functions ( link ).有关底部(链接)或不安全函数(链接)的文章,请参阅 Haskell Wiki。
I wonder if it is possible to create such a type constructor using a richer type system, such as Agda or Haskell with various extensions.我想知道是否可以使用更丰富的类型系统来创建这样的类型构造函数,例如具有各种扩展的 Agda 或 Haskell。
A type constructor which is an Applicative, but not a Monad:一个类型构造函数,它是一个 Applicative,但不是一个 Monad:
newtype T a = T {multidimensional array of a}
You can make an Applicative out of it, with something like:你可以用它来制作一个 Applicative,比如:
mkarray [(+10), (+100), id] <*> mkarray [1, 2]
== mkarray [[11, 101, 1], [12, 102, 2]]
But if you make it a monad, you could get a dimension mismatch.但是如果你让它成为一个 monad,你可能会遇到维度不匹配。 I suspect that examples like this are rare in practice.
我怀疑这样的例子在实践中很少见。
A type constructor which is a Monad:一个类型构造函数,它是一个 Monad:
[]
About Arrows:关于箭头:
Asking where an Arrow lies on this hierarchy is like asking what kind of shape "red" is.询问箭头在此层次结构上的位置就像询问“红色”是什么形状。 Note the kind mismatch:
注意种类不匹配:
Functor :: * -> *
Applicative :: * -> *
Monad :: * -> *
but,但,
Arrow :: * -> * -> *
My style may be cramped by my phone, but here goes.我的风格可能会被我的手机局促,但在这里。
newtype Not x = Kill {kill :: x -> Void}
cannot be a Functor.不能是函子。 If it were, we'd have
如果是这样,我们会有
kill (fmap (const ()) (Kill id)) () :: Void
and the Moon would be made of green cheese.月亮将由绿色奶酪制成。
Meanwhile同时
newtype Dead x = Oops {oops :: Void}
is a functor是函子
instance Functor Dead where
fmap f (Oops corpse) = Oops corpse
but cannot be applicative, or we'd have但不能适用,否则我们会有
oops (pure ()) :: Void
and Green would be made of Moon cheese (which can actually happen, but only later in the evening).而 Green 将由 Moon cheese 制成(这实际上可能发生,但只能在晚上晚些时候)。
(Extra note: Void
, as in Data.Void
is an empty datatype. If you try to use undefined
to prove it's a Monoid, I'll use unsafeCoerce
to prove that it isn't.) (额外注意:
Void
,如Data.Void
是一个空数据类型。如果你尝试使用undefined
来证明它是 Monoid,我将使用unsafeCoerce
来证明它不是。)
Joyously,欣喜若狂,
newtype Boo x = Boo {boo :: Bool}
is applicative in many ways, eg, as Dijkstra would have it,在很多方面都适用,例如,正如 Dijkstra 所说,
instance Applicative Boo where
pure _ = Boo True
Boo b1 <*> Boo b2 = Boo (b1 == b2)
but it cannot be a Monad.但它不能是一个 Monad。 To see why not, observe that return must be constantly
Boo True
or Boo False
, and hence that要知道为什么不,请观察 return 必须始终为
Boo True
或Boo False
,因此
join . return == id
cannot possibly hold.不可能持有。
Oh yeah, I nearly forgot哦对了,差点忘了
newtype Thud x = The {only :: ()}
is a Monad.是一个单子。 Roll your own.
自己卷。
Plane to catch...赶飞机...
I believe the other answers missed some simple and common examples:我相信其他答案遗漏了一些简单而常见的例子:
A type constructor which is a Functor but not an Applicative.一个类型构造函数,它是一个 Functor 但不是一个 Applicative。 A simple example is a pair:
一个简单的例子是一对:
instance Functor ((,) r) where
fmap f (x,y) = (x, f y)
But there is no way how to define its Applicative
instance without imposing additional restrictions on r
.但是没有办法如何定义它的
Applicative
实例而不对r
施加额外的限制。 In particular, there is no way how to define pure :: a -> (r, a)
for an arbitrary r
.特别是,无法为任意
r
定义pure :: a -> (r, a)
。
A type constructor which is an Applicative, but is not a Monad.一个类型构造函数,它是一个 Applicative,但不是一个 Monad。 A well-known example is ZipList .
一个众所周知的例子是ZipList 。 (It's a
newtype
that wraps lists and provides different Applicative
instance for them.) (这是一个
newtype
一个包装清单,并提供不同的Applicative
为他们的实例。)
fmap
is defined in the usual way. fmap
以通常的方式定义。 But pure
and <*>
are defined as但
pure
和<*>
被定义为
pure x = ZipList (repeat x)
ZipList fs <*> ZipList xs = ZipList (zipWith id fs xs)
so pure
creates an infinite list by repeating the given value, and <*>
zips a list of functions with a list of values - applies i -th function to i -th element. so
pure
通过重复给定的值创建一个无限列表,并且<*>
使用值列表压缩函数列表 - 将第i个函数应用于第i个元素。 (The standard <*>
on []
produces all possible combinations of applying i -th function to j -th element.) But there is no sensible way how to define a monad (see this post ). (
[]
上的标准<*>
产生将第i个函数应用于第j个元素的所有可能组合。)但是没有明智的方法来定义 monad(请参阅这篇文章)。
How arrows fit into the functor/applicative/monad hierarchy?箭头如何适应 functor/applicative/monad 层次结构? See Idioms are oblivious, arrows are meticulous, monads are promiscuous by Sam Lindley, Philip Wadler, Jeremy Yallop.
参见 Sam Lindley、Philip Wadler、Jeremy Yallop 的习语是无知的,箭头是细致的,单子是混杂的。 MSFP 2008. (They call applicative functors idioms .) The abstract:
MSFP 2008。(他们称应用函子成语。)摘要:
We revisit the connection between three notions of computation: Moggi's monads, Hughes's arrows and McBride and Paterson's idioms (also called applicative functors).
我们重新审视计算的三个概念之间的联系:Moggi 的单子、Hughes 的箭头以及 McBride 和 Paterson 的习语(也称为应用函子)。 We show that idioms are equivalent to arrows that satisfy the type isomorphism A ~> B = 1 ~> (A -> B) and that monads are equivalent to arrows that satisfy the type isomorphism A ~> B = A -> (1 ~> B).
我们证明了习语等价于满足类型同构 A ~> B = 1 ~> (A -> B) 的箭头,并且单子等价于满足类型同构 A ~> B = A -> (1 ~ > B)。 Further, idioms embed into arrows and arrows embed into monads.
此外,习语嵌入到箭头中,而箭头嵌入到单子中。
一个不是函子的类型构造函数的一个很好的例子是Set
:你不能实现fmap :: (a -> b) -> fa -> fb
,因为没有额外的约束Ord b
你不能构造fb
。
I'd like to propose a more systematic approach to answering this question, and also to show examples that do not use any special tricks like the "bottom" values or infinite data types or anything like that.我想提出一种更系统的方法来回答这个问题,并展示一些不使用任何特殊技巧的例子,比如“底部”值或无限数据类型或类似的东西。
In general, there are two reasons why a type constructor could fail to have an instance of a certain type class:通常,类型构造函数无法拥有某个类型类的实例有两个原因:
Examples of the first kind are easier than those of the second kind because for the first kind, we just need to check whether one can implement a function with a given type signature, while for the second kind, we are required to prove that no implementation could possibly satisfy the laws.第一种的例子比第二种容易,因为对于第一种,我们只需要检查一个给定类型签名的函数是否可以实现,而对于第二种,我们需要证明没有实现可能满足法律。
A type constructor that cannot have a functor instance because the type cannot be implemented:由于无法实现类型而不能具有函子实例的类型构造函数:
data F za = F (a -> z)
This is a contrafunctor, not a functor, with respect to the type parameter a
, because a
in a contravariant position.对于类型参数
a
,这是一个反函子,而不是函子,因为a
处于逆变位置。 It is impossible to implement a function with type signature (a -> b) -> F za -> F zb
.不可能实现具有类型签名
(a -> b) -> F za -> F zb
的函数。
A type constructor that is not a lawful functor even though the type signature of fmap
can be implemented:即使可以实现
fmap
的类型签名,也不是合法函子的类型构造函数:
data Q a = Q(a -> Int, a) fmap :: (a -> b) -> Q a -> Q b fmap f (Q(g, x)) = Q(\\_ -> gx, fx) -- this fails the functor laws!
The curious aspect of this example is that we can implement fmap
of the correct type even though F
cannot possibly be a functor because it uses a
in a contravariant position.这个例子的奇怪之处在于我们可以实现正确类型的
fmap
,即使F
不可能是一个函子,因为它在逆变位置使用a
a。 So this implementation of fmap
shown above is misleading - even though it has the correct type signature (I believe this is the only possible implementation of that type signature), the functor laws are not satisfied.因此,
fmap
显示的fmap
实现具有误导性 - 即使它具有正确的类型签名(我相信这是该类型签名的唯一可能实现),但不满足函子定律。 For example, fmap id
≠ id
, because let (Q(f,_)) = fmap id (Q(read,"123")) in f "456"
is 123
, but let (Q(f,_)) = id (Q(read,"123")) in f "456"
is 456
.例如
fmap id
≠ id
,因为let (Q(f,_)) = fmap id (Q(read,"123")) in f "456"
是123
,但是let (Q(f,_)) = id (Q(read,"123")) in f "456"
是456
。
In fact, F
is only a profunctor, - it is neither a functor nor a contrafunctor.事实上,
F
只是一个 profunctor,——它既不是一个函子也不是一个反函子。
A lawful functor that is not applicative because the type signature of pure
cannot be implemented: take the Writer monad (a, w)
and remove the constraint that w
should be a monoid.一个不适用的合法函子,因为不能实现
pure
的类型签名:取 Writer monad (a, w)
并删除w
应该是幺半群的约束。 It is then impossible to construct a value of type (a, w)
out of a
.它是那么不可能构造类型的值
(a, w)
的出a
。
A functor that is not applicative because the type signature of <*>
cannot be implemented: data F a = Either (Int -> a) (String -> a)
.一个不适用的函子,因为
<*>
的类型签名无法实现: data F a = Either (Int -> a) (String -> a)
。
A functor that is not lawful applicative even though the type class methods can be implemented:即使可以实现类型类方法,也不能合法应用的函子:
data P a = P ((a -> Int) -> Maybe a)
The type constructor P
is a functor because it uses a
only in covariant positions.类型构造函数
P
是一个函子,因为它只在协变位置使用a
。
instance Functor P where
fmap :: (a -> b) -> P a -> P b
fmap fab (P pa) = P (\q -> fmap fab $ pa (q . fab))
The only possible implementation of the type signature of <*>
is a function that always returns Nothing
: <*>
类型签名的唯一可能实现是一个总是返回Nothing
的函数:
(<*>) :: P (a -> b) -> P a -> P b
(P pfab) <*> (P pa) = \_ -> Nothing -- fails the laws!
But this implementation does not satisfy the identity law for applicative functors.但是这个实现并不满足应用函子的恒等律。
Applicative
but not a Monad
because the type signature of bind
cannot be implemented.Applicative
但不是Monad
函子,因为无法实现bind
的类型签名。 I do not know any such examples!我不知道任何这样的例子!
Applicative
but not a Monad
because laws cannot be satisfied even though the type signature of bind
can be implemented.Applicative
但不是Monad
函子,因为即使可以实现bind
的类型签名,也无法满足法律。 This example has generated quite a bit of discussion, so it is safe to say that proving this example correct is not easy.这个例子引起了很多讨论,所以可以肯定地说,证明这个例子是正确的并不容易。 But several people have verified this independently by different methods.
但是有几个人已经通过不同的方法独立验证了这一点。 See Is `data PoE a = Empty |
请参阅是`数据PoE a = 空| Pair aa` a monad?
一对aa`一个monad? for additional discussion.
以供进一步讨论。
data B a = Maybe (a, a)
deriving Functor
instance Applicative B where
pure x = Just (x, x)
b1 <*> b2 = case (b1, b2) of
(Just (x1, y1), Just (x2, y2)) -> Just((x1, x2), (y1, y2))
_ -> Nothing
It is somewhat cumbersome to prove that there is no lawful Monad
instance.证明不存在合法的
Monad
实例有点麻烦。 The reason for the non-monadic behavior is that there is no natural way of implementing bind
when a function f :: a -> B b
could return Nothing
or Just
for different values of a
.非 monadic 行为的原因是,当函数
f :: a -> B b
可以为不同的a
值返回Nothing
或Just
, Nothing
实现bind
自然方式。
It is perhaps clearer to consider Maybe (a, a, a)
, which is also not a monad, and to try implementing join
for that.考虑
Maybe (a, a, a)
可能更清楚,它也不是单子,并尝试为此实现join
。 One will find that there is no intuitively reasonable way of implementing join
.人们会发现没有一种直观合理的方式来实现
join
。
join :: Maybe (Maybe (a, a, a), Maybe (a, a, a), Maybe (a, a, a)) -> Maybe (a, a, a)
join Nothing = Nothing
join Just (Nothing, Just (x1,x2,x3), Just (y1,y2,y3)) = ???
join Just (Just (x1,x2,x3), Nothing, Just (y1,y2,y3)) = ???
-- etc.
In the cases indicated by ???
在用
???
表示的情况下, it seems clear that we cannot produce Just (z1, z2, z3)
in any reasonable and symmetric manner out of six different values of type a
. ,很明显,我们不能从类型
a
的六个不同值中以任何合理和对称的方式产生Just (z1, z2, z3)
。 We could certainly choose some arbitrary subset of these six values, -- for instance, always take the first nonempty Maybe
- but this would not satisfy the laws of the monad.我们当然可以选择这六个值的任意子集,例如,总是取第一个非空的
Maybe
- 但这将不满足单子定律。 Returning Nothing
will also not satisfy the laws.返回
Nothing
也不会满足的法律。
bind
- but fails the identity laws.bind
关联性 - 但不符合恒等律。 The usual tree-like monad (or "a tree with functor-shaped branches") is defined as通常的树状单子(或“具有函子形分支的树”)被定义为
data Tr f a = Leaf a | Branch (f (Tr f a))
This is a free monad over the functor f
.这是一个基于函子
f
的自由单子。 The shape of the data is a tree where each branch point is a "functor-ful" of subtrees.数据的形状是一棵树,其中每个分支点都是子树的“函子”。 The standard binary tree would be obtained with
type fa = (a, a)
.标准二叉树将通过
type fa = (a, a)
。
If we modify this data structure by making also the leaves in the shape of the functor f
, we obtain what I call a "semimonad" - it has bind
that satisfies the naturality and the associativity laws, but its pure
method fails one of the identity laws.如果我们通过将叶子也做成函子
f
的形状来修改这个数据结构,我们就会得到我所说的“semimonad”——它具有满足自然性和结合律的bind
,但它的pure
方法失败了其中一个身份法律。 "Semimonads are semigroups in the category of endofunctors, what's the problem?" “半单子是内函子范畴的半群,有什么问题?” This is the type class
Bind
.这是类型类
Bind
。
For simplicity, I define the join
method instead of bind
:为简单起见,我定义了
join
方法而不是bind
:
data Trs f a = Leaf (f a) | Branch (f (Trs f a))
join :: Trs f (Trs f a) -> Trs f a
join (Leaf ftrs) = Branch ftrs
join (Branch ftrstrs) = Branch (fmap @f join ftrstrs)
The branch grafting is standard, but the leaf grafting is non-standard and produces a Branch
.接枝是标准的,但接叶是非标准的,产生一个
Branch
。 This is not a problem for the associativity law but breaks one of the identity laws.这对于结合律来说不是问题,而是违反了恒等律之一。
Neither of the functors Maybe (a, a)
and Maybe (a, a, a)
can be given a lawful Monad
instance, although they are obviously Applicative
.函子
Maybe (a, a)
和Maybe (a, a, a)
都不能被赋予合法的Monad
实例,尽管它们显然是Applicative
。
These functors have no tricks - no Void
or bottom
anywhere, no tricky laziness/strictness, no infinite structures, and no type class constraints.这些函子没有技巧——任何地方都没有
Void
或bottom
,没有棘手的懒惰/严格,没有无限结构,也没有类型类约束。 The Applicative
instance is completely standard. Applicative
实例是完全标准的。 The functions return
and bind
can be implemented for these functors but will not satisfy the laws of the monad.函数
return
和bind
可以为这些函子实现,但不满足 monad 的定律。 In other words, these functors are not monads because a specific structure is missing (but it is not easy to understand what exactly is missing).换句话说,这些函子不是 monad,因为缺少特定的结构(但并不容易理解到底缺少什么)。 As an example, a small change in the functor can make it into a monad:
data Maybe a = Nothing | Just a
举个例子,函子的一个小改动就可以使它变成一个 monad:
data Maybe a = Nothing | Just a
data Maybe a = Nothing | Just a
is a monad. data Maybe a = Nothing | Just a
是一个单子。 Another similar functor data P12 a = Either a (a, a)
is also a monad.另一个类似的函子
data P12 a = Either a (a, a)
也是一个 monad。
In general, here are some constructions that produce lawful Monad
s out of polynomial types.一般来说,这里有一些构造可以从多项式类型中产生合法的
Monad
。 In all these constructions, M
is a monad:在所有这些结构中,
M
是一个 monad:
type M a = Either c (w, a)
where w
is any monoid type M a = Either c (w, a)
其中w
是任何幺半群type M a = m (Either c (w, a))
where m
is any monad and w
is any monoid type M a = m (Either c (w, a))
其中m
是任何单子, w
是任何幺半群type M a = (m1 a, m2 a)
where m1
and m2
are any monads type M a = (m1 a, m2 a)
其中m1
和m2
是任何单子type M a = Either a (ma)
where m
is any monad type M a = Either a (ma)
其中m
是任何 monad The first construction is WriterT w (Either c)
, the second construction is WriterT w (EitherT cm)
.第一个结构是
WriterT w (Either c)
,第二个结构是WriterT w (EitherT cm)
。 The third construction is a component-wise product of monads: pure @M
is defined as the component-wise product of pure @m1
and pure @m2
, and join @M
is defined by omitting cross-product data (eg m1 (m1 a, m2 a)
is mapped to m1 (m1 a)
by omitting the second part of the tuple):第三种构造是 monad 的组件方式乘积:
pure @M
定义为pure @m1
和pure @m2
的组件方式乘积, join @M
定义为省略交叉乘积数据(例如m1 (m1 a, m2 a)
通过省略元组的第二部分映射到m1 (m1 a)
):
join :: (m1 (m1 a, m2 a), m2 (m1 a, m2 a)) -> (m1 a, m2 a)
join (m1x, m2x) = (join @m1 (fmap fst m1x), join @m2 (fmap snd m2x))
The fourth construction is defined as第四个结构定义为
data M m a = Either a (m a)
instance Monad m => Monad M m where
pure x = Left x
join :: Either (M m a) (m (M m a)) -> M m a
join (Left mma) = mma
join (Right me) = Right $ join @m $ fmap @m squash me where
squash :: M m a -> m a
squash (Left x) = pure @m x
squash (Right ma) = ma
I have checked that all four constructions produce lawful monads.我已经检查过所有四种结构都产生了合法的 monad。
I conjecture that there are no other constructions for polynomial monads.我猜想多项式单子没有其他构造。 For example, the functor
Maybe (Either (a, a) (a, a, a, a))
is not obtained through any of these constructions and so is not monadic.例如,函子
Maybe (Either (a, a) (a, a, a, a))
不是通过任何这些构造获得的,因此不是一元的。 However, Either (a, a) (a, a, a)
is monadic because it is isomorphic to the product of three monads a
, a
, and Maybe a
.然而,
Either (a, a) (a, a, a)
是单子的,因为它同构于三个单子a
、 a
和Maybe a
的乘积。 Also, Either (a,a) (a,a,a,a)
is monadic because it is isomorphic to the product of a
and Either a (a, a, a)
.此外,
Either (a,a) (a,a,a,a)
是一元的,因为它同构于a
和Either a (a, a, a)
的乘积。
The four constructions shown above will allow us to obtain any sum of any number of products of any number of a
's, for example Either (Either (a, a) (a, a, a, a)) (a, a, a, a, a))
and so on.以上所示的四个构造将允许我们获得任何数量的任何数量的产品的任何总和
a
的,例如Either (Either (a, a) (a, a, a, a)) (a, a, a, a, a))
等等。 All such type constructors will have (at least one) Monad
instance.所有这样的类型构造函数都会有(至少一个)
Monad
实例。
It remains to be seen, of course, what use cases might exist for such monads.当然,对于此类 monad 可能存在哪些用例还有待观察。 Another issue is that the
Monad
instances derived via constructions 1-4 are in general not unique.另一个问题是通过结构 1-4 派生的
Monad
实例通常不是唯一的。 For example, the type constructor type F a = Either a (a, a)
can be given a Monad
instance in two ways: by construction 4 using the monad (a, a)
, and by construction 3 using the type isomorphism Either a (a, a) = (a, Maybe a)
.例如,类型构造函数
type F a = Either a (a, a)
可以通过两种方式被赋予一个Monad
实例:通过使用 monad (a, a)
构造 4,以及通过使用类型同构的构造 3 Either a (a, a) = (a, Maybe a)
。 Again, finding use cases for these implementations is not immediately obvious.同样,为这些实现找到用例并不是很明显。
A question remains - given an arbitrary polynomial data type, how to recognize whether it has a Monad
instance.一个问题仍然存在 - 给定任意多项式数据类型,如何识别它是否具有
Monad
实例。 I do not know how to prove that there are no other constructions for polynomial monads.我不知道如何证明多项式单子没有其他构造。 I don't think any theory exists so far to answer this question.
我认为到目前为止还没有任何理论可以回答这个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.