简体   繁体   English

stackage.org 上是否有 `liftA2` 和 `<*>` 的非循环定义

[英]Is there a non cyclic definition for `liftA2` and `<*>` on stackage.org

On stackage.org , the following cyclic declaration exists for liftA2 and <*> for the Applicative typeclass.stackage.org 上,对于liftA2<*> Applicative类型类存在以下循环声明。

       (<*>) = liftA2 id
liftA2 f x y = f <$> x <*> y

Is a non-cyclic declaration available for liftA2 or <*> on the site.是一个可用于网站上的liftA2<*>的非循环声明。 Are such completely cyclic references an oversight?这种完全循环的引用是一种疏忽吗?

UPDATE:更新:

The following (necessary) clarifying declarations seems to be missing from hoogle docs: hoogle文档中似乎缺少以下(必要的)澄清声明:

<*> :: Functor F => F (a -> b) -> F a -> F b

and by implication (due to cyclic declaration)并暗示(由于循环声明)

liftA2 :: Functor F => (a -> b -> c) -> F a -> F b -> F c

[…] the following cyclic definition exists for liftA2 and <*> for the Applicative type class. […] Applicative类型 class 的liftA2<*>存在以下循环定义。

 (<*>) = liftA2 id liftA2 fxy = f <$> x <*> y

Is a non-cyclic definition available for liftA2 or <*> on the site.网站上的liftA2<*>是可用的非循环定义。

These aren't definitions of the methods, exactly;确切地说,这些不是方法的定义; they're default definitions.它们是默认定义。 A typeclass with one parameter is just a set of types, and an instance definition is the price of admission for membership in the set.具有一个参数的类型类只是一组类型,而instance定义是该集合成员资格的入场费。 The Minimal pragma for Applicative tells you that you must implement one of these two methods, and that information is displayed in Haddock documentation. ApplicativeMinimal pragma 告诉您必须实现这两种方法之一,并且该信息显示在 Haddock 文档中。

The actual definitions of liftA2 , <*> , and pure are specific to the instances of Applicative . liftA2<*>pure的实际定义特定于Applicative的实例。 Generally speaking, if a typeclass contains methods that can be implemented using only the other methods of the typeclass, then that method doesn't strictly need to be part of the class, since it could be a top-level definition with a constraint.一般来说,如果一个类型类包含可以仅使用该类型类的其他方法实现的方法,那么该方法不需要严格地成为 class 的一部分,因为它可以是具有约束的顶级定义。

However, such a method may be included anyway.然而,无论如何都可以包括这样的方法。 This may be just for convenience, when it's easier to define an instance in terms of one function even though it's not the “most fundamental” operation.这可能只是为了方便,因为它更容易根据 function 定义一个实例,即使它不是“最基本的”操作。 It's also often for performance reasons: redundant methods tend to be included when it's possible to implement a method more efficiently than the default for a particular type.这通常也是出于性能原因:当可以比特定类型的默认方法更有效地实现方法时,往往会包含冗余方法。 In this case, for example, liftA2 may be able to traverse two structures together more efficiently than traversing one with <$> and then the other separately with <*> .在这种情况下,例如, liftA2可能能够更有效地一起遍历两个结构,而不是使用<$>遍历一个结构,然后使用<*>单独遍历另一个结构。

GHC also offers DefaultSignatures as a way to add more specific defaults, typically defined in terms of Generic , but this only lets you add typeclass constraints, largely for convenience with deriving . GHC 还提供DefaultSignatures作为添加更多特定默认值的一种方式,通常根据Generic定义,但这仅允许您添加类型类约束,主要是为了方便deriving

Are such completely cyclic references an oversight?这种完全循环的引用是一种疏忽吗?

Not at all, they're intentional.一点也不,他们是故意的。 Cyclic definitions in default implementations of typeclass methods are quite common.类型类方法的默认实现中的循环定义非常普遍。 For example, Eq is defined in the Haskell Report something like this:例如, Eq在 Haskell 报告中定义如下:

class Eq a where
  (==) :: a -> a -> Bool
  x == y = not (x /= y)

  (/=) :: a -> a -> Bool
  x /= y = not (x == y)

It is possible to forget to implement one of these, so that they both use the default, and thus represent an infinite loop, however:可能会忘记实现其中之一,因此它们都使用默认值,因此代表一个无限循环,但是:

  • This generates a warning by default ( -Wmissing-methods is enabled by -Wdefault ).默认情况下,这会生成一个警告( -Wmissing-methods-Wdefault启用)。

  • If a Minimal pragma is not specified, all of the methods in the class are assumed to be required.如果未指定Minimal pragma,则假定 class 中的所有方法都是必需的。

So really the only other options in this case are to remove one or the other from the class, or omit providing a default for one of them.因此,在这种情况下,实际上唯一的其他选项是从 class 中删除一个或另一个,或者省略为其中一个提供默认值。 If you want to know about how these methods are implemented for Applicative , the thing to look at is the instance implementations for concrete type constructors like [] , ZipList , Maybe , StateT , and so on.如果您想了解这些方法是如何为Applicative实现的,那么要看的是具体类型构造函数的instance实现,例如[]ZipListMaybeStateT等。

Is a non-cyclic definition available for liftA2? LiftA2 是否有非循环定义?

The implementations of (<*>) and liftA2 are specific to the instances of the Applicative typeclass. (<*>)liftA2的实现特定于Applicative类型类的实例 Indeed, for each Applicative instance you need to implement pure , and (<*>) or liftA2 , or as specified by the MINIMAL pragma:实际上,对于每个Applicative实例,您需要实现pure(<*>)liftA2 ,或者由MINIMAL pragma 指定:

 class Functor f => Applicative f where {-# MINIMAL pure, ((<*>) | liftA2) #-} -- …

For example for the Maybe instance of Applicative , this is implemented as:例如,对于ApplicativeMaybe实例,它被实现为:

 instance Applicative Maybe where pure = Just Just f <*> m = fmap fm Nothing <*> _m = Nothing liftA2 f (Just x) (Just y) = Just (fxy) liftA2 _ _ _ = Nothing Just _m1 *> m2 = m2 Nothing *> _m2 = Nothing

Simply implementing pure and (<*>) would here be sufficient, since then liftA2 is implemented in terms of (<*>) .在这里简单地实现pure(<*>)就足够了,因为那时liftA2是根据(<*>)实现的。 It is however often more efficient to implement the other methods as well.然而,执行其他方法通常更有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM