Geo*_*rge 2 haskell hoogle stackage
在stackage.org,下面的循环声明存在liftA2
和<*>
对Applicative
类型类。
(<*>) = liftA2 id
liftA2 f x y = f <$> x <*> y
Run Code Online (Sandbox Code Playgroud)
是可用于现场liftA2
或<*>
现场的非循环声明。这种完全循环的引用是一种疏忽吗?
更新:
hoogle
文档中似乎缺少以下(必要的)澄清声明:
<*> :: Functor F => F (a -> b) -> F a -> F b
Run Code Online (Sandbox Code Playgroud)
并暗示(由于循环声明)
liftA2 :: Functor F => (a -> b -> c) -> F a -> F b -> F c
Run Code Online (Sandbox Code Playgroud)
[...] 存在以下循环定义用于
liftA2
和<*>
用于Applicative
类型类。Run Code Online (Sandbox Code Playgroud)(<*>) = liftA2 id liftA2 f x y = f <$> x <*> y
是可用于站点
liftA2
或<*>
站点上的非循环定义。
确切地说,这些不是方法的定义;它们是默认定义。带有一个参数的类型类只是一组类型,而instance
定义是该组成员资格的入场价格。在Minimal
编译的Applicative
告诉你,你必须实现这两种方法中的一种,并将该信息显示黑线鳕文档。
实际的定义liftA2
,<*>
以及pure
专用于的实例Applicative
。一般来说,如果一个类型类包含只能使用该类型类的其他方法实现的方法,那么该方法并不严格需要是该类的一部分,因为它可以是具有约束的顶级定义。
然而,无论如何都可以包括这样的方法。这可能只是为了方便,当根据一个函数定义一个实例时更容易,即使它不是“最基本的”操作。这通常也是出于性能原因:当可以比特定类型的默认方法更有效地实现方法时,往往会包含冗余方法。在这种情况下,例如,liftA2
可以是能够在两个结构遍历在一起的效率比遍历一个与<$>
然后其他分别与<*>
。
GHC 还提供DefaultSignatures
了一种添加更多特定默认值的方法,通常用 定义Generic
,但这只能让您添加类型类约束,主要是为了方便使用deriving
.
这种完全循环的引用是一种疏忽吗?
完全没有,他们是故意的。类型类方法的默认实现中的循环定义非常常见。例如,Eq
在 Haskell 报告中定义如下:
class Eq a where
(==) :: a -> a -> Bool
x == y = not (x /= y)
(/=) :: a -> a -> Bool
x /= y = not (x == y)
Run Code Online (Sandbox Code Playgroud)
有可能忘记实现其中之一,因此它们都使用默认值,从而表示无限循环,但是:
默认情况下会生成警告(-Wmissing-methods
由 启用-Wdefault
)。
如果Minimal
未指定编译指示,则假定类中的所有方法都是必需的。
因此,在这种情况下,实际上唯一的其他选项是从类中删除一个或另一个,或者省略为其中一个提供默认值。如果您想了解如何为 实现这些方法Applicative
,则需要查看instance
具体类型构造函数(如[]
、ZipList
、Maybe
、StateT
等)的实现。