下面是一个函数的定义:
fmap :: (a -> b) -> f a -> f b
你们能解释一下具体是什么意思吗?我不明白的是f a
:f b
为什么可以这样写?我的意思是,为什么它语法正确并且编译良好?
我认为应该只有一个变量(a -> b) -> a -> b
或(a -> b) -> f -> f
其他(a -> b) -> c -> d
再一次,问题不在于函数的含义,而在于语法是否正确。
下面是一个函数的定义:
fmap :: (a -> b) -> f a -> f b
你们能解释一下具体是什么意思吗?我不明白的是f a
:f b
为什么可以这样写?我的意思是,为什么它语法正确并且编译良好?
我认为应该只有一个变量(a -> b) -> a -> b
或(a -> b) -> f -> f
其他(a -> b) -> c -> d
再一次,问题不在于函数的含义,而在于语法是否正确。
您接受“正常”map
功能的签名map :: (a -> b) -> [a] -> [b]
吗?
现在假设不是[a]
我们写了List a
(与 比较Maybe a
),所以签名读的是map :: (a -> b) -> List a -> List b
。此签名在带有 的表格(a -> b) -> f a -> f b
上f = List
。
该函数fmap :: (a -> b) -> f a -> f b
是map
对其他类型构造函数(如Maybe
.
那么 Haskell[1] 类型签名由 3 个元素组成
现在,对于您的示例,我们有 2 个元素。a
, b
, 和f
是类型变量,然后我们有函数箭头。
a
并b
具有 kind *
,这意味着它们可以按原样由具体类型实例化。f
另一方面,有种类* -> *
[2]。这意味着f
不能以与 and 相同的方式实例a
化b
。它需要用一个类型实例化,该类型采用一种类型,*
然后产生一个具体类型。
例如,Maybe
必须先给出另一种类型,比如Int
,然后才能构造该类型的值。例如Just 1 :: Maybe Int
,但wat :: Maybe
没有意义。因此,应用程序f a
与将值函数f
应用于 value相同a
,但类型除外。你甚至有部分应用!
所以读f a -> f b
作“一个函数,它将采用某种类型f
,将其应用于某种类型a
,并返回一个f
应用于某种类型的类型值b
”。
[1] 哈斯克尔我的意思是香草哈斯克尔。类型运算符、对 N 个类型进行排序等使事情变得复杂。
[2] 这不是正常功能->
。它谈论的是类型而不是值。
Haskell 中的语法Type1 Type2
意味着类型的应用。例如,您可能已经看到 type Maybe Integer
。它的工作原理Maybe
是这样定义的:
data Maybe a = ...
注意类型变量a
。这意味着我们必须先应用于Maybe
某种类型,然后才能将其用作类型本身。在Maybe Integer
中,这a
被设置为Integer
。
现在在问题中,我们有f a
,即一个类型变量应用于另一个类型变量。这意味着f
可以是Maybe
期望应用于另一种类型的a
东西,并且可以是Integer
本身就是一种类型的东西。