首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >stackage.org上是否有`liftA2‘和`<*>`的非循环定义

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

Stack Overflow用户
提问于 2021-04-15 04:34:58
回答 1查看 129关注 0票数 2

stackage.org上,对于liftA2存在以下循环声明,对于Applicative类型类存在<*>循环声明。

代码语言:javascript
复制
       (<*>) = liftA2 id
liftA2 f x y = f <$> x <*> y

是站点上可用于liftA2<*>的非循环声明。这种完全循环的引用是一种疏忽吗?

更新:

hoogle文档中似乎缺少以下(必要的)澄清声明:

代码语言:javascript
复制
<*> :: Functor F => F (a -> b) -> F a -> F b

并且隐含(由于循环声明)

代码语言:javascript
复制
liftA2 :: Functor F => (a -> b -> c) -> F a -> F b -> F c
EN

回答 1

Stack Overflow用户

发布于 2021-04-15 05:45:52

…对于Applicative类型类的liftA2<*>,存在以下循环定义。

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

是可用于站点上的liftA2<*>的非循环定义。

确切地说,这些不是方法的定义;它们是默认的定义。只有一个参数的类型类只是一组类型,而instance定义是该集合中成员资格的入场费。Haddock的Minimal杂注告诉您必须实现这两个方法中的一个,该信息显示在Applicative文档中。

liftA2<*>pure的实际定义特定于Applicative实例。一般而言,如果一个类型类包含只能使用该类型类的其他方法实现的方法,则该方法不需要严格地成为该类的一部分,因为它可以是具有约束的顶级定义。

但是,无论如何都可以包含这样的方法。这可能只是为了方便,即使它不是“最基本的”操作,但在一个函数中定义实例会更容易。这通常也是出于性能原因:当可以比特定类型的缺省方法更有效地实现方法时,往往会包含冗余方法。例如,在这种情况下,与使用<$>遍历一个结构,然后使用<*>分别遍历另一个结构相比,liftA2可能能够更有效地一起遍历两个结构。

GHC还提供了DefaultSignatures作为添加更多特定默认值的方法,这些默认值通常是根据Generic定义的,但这只允许您添加类型类约束,这主要是为了方便使用deriving

这样的完全循环引用是一个疏忽吗?

一点也不,他们是故意的。在类型类方法的默认实现中,循环定义是很常见的。例如,Eq在Haskell报告中定义如下:

代码语言:javascript
复制
class Eq a where
  (==) :: a -> a -> Bool
  x == y = not (x /= y)

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

但是,可能会忘记实现其中的一个,因此它们都使用默认值,因此表示无限循环:

默认情况下,此选项会生成警告( -Wdefault).启用

  • 如果未指定Minimal杂注,则假定类中的所有方法都是必需的。

因此,在这种情况下,实际上唯一的其他选择是从类中删除一个或另一个,或者省略为其中一个提供默认值。如果您想了解这些方法是如何为Applicative实现的,那么需要查看的是具体类型构造函数的instance实现,比如[]ZipListMaybeStateT等等。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67098759

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档