围绕 Haskell 类型系统的术语说明
Clarification of Terms around Haskell Type system
haskell 中的类型系统似乎非常重要,我想澄清一些围绕 haskell 类型系统的术语。
一些类型 classes
Functor
Applicative
Monad
使用:info
后发现Functor
是class的类型,Applicative
是class和=>
的类型(推导?) Functor
和 Monad
派生 Applicative
类型 class.
我读到 Maybe
是一个 Monad,这是否意味着 Maybe
也是 Applicative
和 Functor
?
->
运算符
当我定义类型时
data Maybe = Just a | Nothing
并检查 :t Just
我得到 Just :: a -> Maybe a
。如何阅读这个 ->
运算符?
它让我对函数感到困惑,其中 a -> b
意味着它计算 a
到 b
(可能是 returns)——我倾向于认为 lhs 到 rhs关联但在定义类型时会发生变化?
术语类型以模棱两可的方式使用,类型,类型Class,类型构造函数,具体类型等...我想知道它们的确切含义
确实,“类型”这个词的用法有些含糊。
也许最实用的看待它的方法是 类型 只是一组 值 。例如,Bool
是包含值 True
和 False
的有限集。
在数学上,set[= 的概念之间存在细微差别153=] 和 type,但对于程序员来说,它们并不重要。但是您通常应该认为集合是无限的,例如 Integer
包含任意大的数字。
定义类型最明显的方法是使用 data
声明,在最简单的情况下,它只列出所有值:
data Colour = Red | Green | Blue
我们有一个类型,作为一个集合,包含三个值。
具体类型基本上就是我们所说的明确我们的意思是上面的意思:对应于一组值的特定类型。 Bool
是具体类型,可以很容易理解为 data
定义,但 String
、Maybe Integer
和 Double -> IO String
也是具体类型,尽管它们不' 对应于任何单个 data
声明。
具体类型不能有的是类型变量†,也不能它是一个不完全应用的类型构造函数。例如,Maybe
不是具体类型。
那么什么是类型构造器?它是值构造函数的类型级模拟。 Haskell 中的“构造函数”在数学上的意思是一个 injective function,即一个函数 f 如果给定 f(x) 你可以清楚地识别出什么是x。此外,假设任何不同的构造函数都具有不相交的范围,这意味着您还可以识别 f.‡
Just
是值构造函数的一个例子,但它使讨论变得复杂,因为它也有一个类型参数。让我们考虑一个简化版本:
data MaybeInt = JustI Int | NothingI
现在我们有
JustI :: Int -> MaybeInt
这就是 JustI
是一个 函数 的原因。就像任何具有相同签名的函数一样,它可以应用于正确类型的参数值,比如,你可以写 JustI 5
.
这个函数是单射的意味着我可以定义一个变量,比如说,
quoxy :: MaybeInt
quoxy = JustI 9328
然后我可以 模式匹配 与 JustI
构造函数:
> case quoxy of { JustI n -> print n }
9328
这对于具有相同签名的通用函数是不可能的:
foo :: Int -> MaybeInt
foo i = JustI $ negate i
> case quoxy of { foo n -> print n }
<interactive>:5:17: error: Parse error in pattern: foo
请注意,构造函数可以是 nullary,在这种情况下,单射 属性 是无意义的,因为没有包含单射函数的数据/参数。 Nothing
和 True
是 nullary 构造函数的示例。
类型构造函数与值构造函数的思想相同:类型级函数 可以进行模式匹配。任何用 data
定义的类型名都是类型构造函数,例如 Bool
、Colour
和 Maybe
都是类型构造函数。 Bool
和 Colour
是无效的,但是 Maybe
是一元类型构造函数:它接受一个类型参数,只有结果才是具体类型。
因此,与值级函数不同,类型级函数在某种程度上是默认类型构造函数。还有一些不是构造函数的类型级函数,但它们需要 -XTypeFamilies
.
一个类型class可以理解为一组类型,同理一个类型可以是被视为一组值。这不是很准确,说 class 是 一组类型构造函数 更接近于真实,但是再次思考数学细节也没有那么有用 - 最好看看示例。
type-as-set-of-values 和 class-as-set-of-types 之间有两个主要区别:
- 如何定义“元素”:在编写
data
声明时,您需要立即描述允许的值。相比之下,class
被定义为“空”,然后 实例 稍后定义,可能在不同的模块中。
- 元素如何使用。
data
类型基本上枚举了所有值,因此它们可以再次被 识别。 类 同时通常不关心识别类型,而是指定元素类型满足的 属性 。这些属性以 方法 或 class 的形式出现。例如,Num
class 的实例是具有 属性 的类型,您可以将元素加在一起。
您可以说,Haskell 在值级别上是静态类型的(每种类型中的固定值集),但在类型级别上是鸭子类型的(classes 只需要有人某个地方实现了必要的方法)。
Num
示例的简化版本:
class Num a where
(+) :: a -> a -> a
instance Num Int where
0 + x = x
x + y = ...
如果 +
运算符尚未在前奏中定义,您现在可以将其与 Int
数字一起使用。稍后,也许在不同的模块中,您还可以将其用于新的自定义数字类型:
data MyNumberType = BinDigits [Bool]
instance Num MyNumberType where
BinDigits [] + BinDigits l = BinDigits l
BinDigits (False:ds) + BinDigits (False:es)
= BinDigits (False : ...)
与 Num
不同,Functor
...Monad
类型 classes 不是 class es 的类型,但是 1-ary 类型构造函数。 IE。每个仿函数都是一个类型构造函数,它接受一个参数使其成为具体类型。例如,回想一下 Maybe
是 1 元类型构造函数。
class Functor f where
fmap :: (a->b) -> f a -> f b
instance Functor Maybe where
fmap f (Just a) = Just (f a)
fmap _ Nothing = Nothing
正如您自己得出的结论,Applicative
是 Functor
的 subclass。 D 是 C 的子class 基本上意味着 D 是C 中的一组类型构造函数。因此,是的,如果 Maybe
是 Monad
的一个实例,它也是 Functor
.
的一个实例
†这不完全正确:如果您将_universal quantor_明确视为类型的一部分,那么具体类型可以包含变量。不过这有点高级。
‡如果使用了 -XPatternSynonyms
扩展名,则不能保证这一点。
haskell 中的类型系统似乎非常重要,我想澄清一些围绕 haskell 类型系统的术语。
一些类型 classes
Functor
Applicative
Monad
使用
:info
后发现Functor
是class的类型,Applicative
是class和=>
的类型(推导?)Functor
和Monad
派生Applicative
类型 class.我读到
Maybe
是一个 Monad,这是否意味着Maybe
也是Applicative
和Functor
?->
运算符当我定义类型时
data Maybe = Just a | Nothing
并检查
:t Just
我得到Just :: a -> Maybe a
。如何阅读这个->
运算符?它让我对函数感到困惑,其中
a -> b
意味着它计算a
到b
(可能是 returns)——我倾向于认为 lhs 到 rhs关联但在定义类型时会发生变化?术语类型以模棱两可的方式使用,类型,类型Class,类型构造函数,具体类型等...我想知道它们的确切含义
确实,“类型”这个词的用法有些含糊。
也许最实用的看待它的方法是 类型 只是一组 值 。例如,Bool
是包含值 True
和 False
的有限集。
在数学上,set[= 的概念之间存在细微差别153=] 和 type,但对于程序员来说,它们并不重要。但是您通常应该认为集合是无限的,例如 Integer
包含任意大的数字。
定义类型最明显的方法是使用 data
声明,在最简单的情况下,它只列出所有值:
data Colour = Red | Green | Blue
我们有一个类型,作为一个集合,包含三个值。
具体类型基本上就是我们所说的明确我们的意思是上面的意思:对应于一组值的特定类型。 Bool
是具体类型,可以很容易理解为 data
定义,但 String
、Maybe Integer
和 Double -> IO String
也是具体类型,尽管它们不' 对应于任何单个 data
声明。
具体类型不能有的是类型变量†,也不能它是一个不完全应用的类型构造函数。例如,Maybe
不是具体类型。
那么什么是类型构造器?它是值构造函数的类型级模拟。 Haskell 中的“构造函数”在数学上的意思是一个 injective function,即一个函数 f 如果给定 f(x) 你可以清楚地识别出什么是x。此外,假设任何不同的构造函数都具有不相交的范围,这意味着您还可以识别 f.‡
Just
是值构造函数的一个例子,但它使讨论变得复杂,因为它也有一个类型参数。让我们考虑一个简化版本:
data MaybeInt = JustI Int | NothingI
现在我们有
JustI :: Int -> MaybeInt
这就是 JustI
是一个 函数 的原因。就像任何具有相同签名的函数一样,它可以应用于正确类型的参数值,比如,你可以写 JustI 5
.
这个函数是单射的意味着我可以定义一个变量,比如说,
quoxy :: MaybeInt
quoxy = JustI 9328
然后我可以 模式匹配 与 JustI
构造函数:
> case quoxy of { JustI n -> print n }
9328
这对于具有相同签名的通用函数是不可能的:
foo :: Int -> MaybeInt
foo i = JustI $ negate i
> case quoxy of { foo n -> print n }
<interactive>:5:17: error: Parse error in pattern: foo
请注意,构造函数可以是 nullary,在这种情况下,单射 属性 是无意义的,因为没有包含单射函数的数据/参数。 Nothing
和 True
是 nullary 构造函数的示例。
类型构造函数与值构造函数的思想相同:类型级函数 可以进行模式匹配。任何用 data
定义的类型名都是类型构造函数,例如 Bool
、Colour
和 Maybe
都是类型构造函数。 Bool
和 Colour
是无效的,但是 Maybe
是一元类型构造函数:它接受一个类型参数,只有结果才是具体类型。
因此,与值级函数不同,类型级函数在某种程度上是默认类型构造函数。还有一些不是构造函数的类型级函数,但它们需要 -XTypeFamilies
.
一个类型class可以理解为一组类型,同理一个类型可以是被视为一组值。这不是很准确,说 class 是 一组类型构造函数 更接近于真实,但是再次思考数学细节也没有那么有用 - 最好看看示例。
type-as-set-of-values 和 class-as-set-of-types 之间有两个主要区别:
- 如何定义“元素”:在编写
data
声明时,您需要立即描述允许的值。相比之下,class
被定义为“空”,然后 实例 稍后定义,可能在不同的模块中。 - 元素如何使用。
data
类型基本上枚举了所有值,因此它们可以再次被 识别。 类 同时通常不关心识别类型,而是指定元素类型满足的 属性 。这些属性以 方法 或 class 的形式出现。例如,Num
class 的实例是具有 属性 的类型,您可以将元素加在一起。
您可以说,Haskell 在值级别上是静态类型的(每种类型中的固定值集),但在类型级别上是鸭子类型的(classes 只需要有人某个地方实现了必要的方法)。
Num
示例的简化版本:
class Num a where
(+) :: a -> a -> a
instance Num Int where
0 + x = x
x + y = ...
如果 +
运算符尚未在前奏中定义,您现在可以将其与 Int
数字一起使用。稍后,也许在不同的模块中,您还可以将其用于新的自定义数字类型:
data MyNumberType = BinDigits [Bool]
instance Num MyNumberType where
BinDigits [] + BinDigits l = BinDigits l
BinDigits (False:ds) + BinDigits (False:es)
= BinDigits (False : ...)
与 Num
不同,Functor
...Monad
类型 classes 不是 class es 的类型,但是 1-ary 类型构造函数。 IE。每个仿函数都是一个类型构造函数,它接受一个参数使其成为具体类型。例如,回想一下 Maybe
是 1 元类型构造函数。
class Functor f where
fmap :: (a->b) -> f a -> f b
instance Functor Maybe where
fmap f (Just a) = Just (f a)
fmap _ Nothing = Nothing
正如您自己得出的结论,Applicative
是 Functor
的 subclass。 D 是 C 的子class 基本上意味着 D 是C 中的一组类型构造函数。因此,是的,如果 Maybe
是 Monad
的一个实例,它也是 Functor
.
†这不完全正确:如果您将_universal quantor_明确视为类型的一部分,那么具体类型可以包含变量。不过这有点高级。
‡如果使用了 -XPatternSynonyms
扩展名,则不能保证这一点。