class Functor f where
fmap :: (a -> b) -> f a -> f b
class (Functor f) => Applicative f where
pure a = f a
<*> :: f (a -> b) -> f a -> f b
我试图理解Haskell中的适用性 根据适用性的定义,它看起来像 Functor
的子类。我认为fmap就像Functor的接口(在Java世界中) 如果来自Functor的 Applicative 子类,则需要实现Functor的fmap,但是 Functor 和 Applicative 中的fmap签名不同
(a -> b) -> f a -> f b
f (a -> b) -> f a -> f b
谁能解释为什么?
答案 0 :(得分:5)
首先,如@paul所述,您正在使用的定义有些偏离。正确的定义如下:
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
那么这些定义应该如何解码?在这里要实现的主要事情是,与Java接口相比,Haskell类型类与Java接口有更多的共同点-因此,这里的Applicative
定义不是在Java意义上定义子类,而是指定类型只能是一个实例。 Applicative
的值,如果它已经是Functor
的实例(即,所有Applicative
也必须实现fmap
,即使它不是Applicative
类型类的一部分)。有关Functor
和Applicative
的更多信息,我强烈推荐在线图书Learn You a Haskell for Great Good,尤其是section on 'Functors, Applicative and Monoid'。
答案 1 :(得分:4)
请参阅Control.Applicative的文档。
的类型签名(<*>) :: f (a -> b) -> f a -> f b
是顺序应用程序运算符<*>
而不是fmap
。
我认为fmap就像Functor的接口(在Java世界中),如果 Functor的应用子类,则需要从 函子
实际上,Applicative
就像Java世界中的接口,更确切地说,就像Java自8以来引入的带有default methods的接口。在Java语法中,如:
public interface Applicative extends Functor {..}
请注意,此处Java中Applicative
的定义不是一个具体的类,它不需要不需要从fmap
接口实现Functor
。
答案 2 :(得分:3)
我认为您正在使用的定义有些偏离(可能是来源有误,或者您可能误解了),这就是造成混淆的原因。
就像@AJFarmar在评论中提到的那样,fmap
是Functor
类型类(或Java术语为Interface)的一部分; Applicative
的定义表明,每当您尝试创建一个Applicative
实例(即实现Applicative
接口)时,您都将尝试为也创建该实例的类型< / em>必须是Functor
的实例(它还必须实现Functor
接口)。因此fmap
的签名将始终为:
fmap :: (a -> b) -> f a -> f b