我刚开始学习一个Haskell,我在一个例子中看到了这个没有解释:
tell :: (Show a) => [a] -> String
Run Code Online (Sandbox Code Playgroud)
这是什么意思,特别是=>?我知道如果我替换->或删除它将无法工作,但我真的不明白为什么.
pig*_*ker 22
这是另一种看待它的方式.某些函数的参数是不可见的,其他参数是可见的.类型input -> output告诉我们可以看到一个可见input的参数.类型(Constraint) => output告诉我们预期会有一些不可见的信息.它们不可互换,因为必须写入可见的参数,并且不能写入不可见的参数.隐形的论据是让编译器为自己弄清楚(好吧,他听起来像是对我而言),他坚持要把它们弄得一团糟:他拒绝被告知它们是什么!
偷偷地说,这个tell例子的完整类型是
tell :: forall (a :: *). (Show a) => [a] -> String
Run Code Online (Sandbox Code Playgroud)
我所做的就是弄清楚这个a变量的来源以及它是什么样的东西.您还可以将其视为"交易":tell为a满足需求的所有类型提供服务(Show a).
为了使用tell有意义,它需要三件事.其中两个是看不见的,一个是可见的.也就是说,在使用时tell,可以使visibile参数显式化,编译器会尝试填充不可见的部分.让我们更慢地完成这种类型的工作.
tell :: forall (a :: *). -- the type of elements to tell (invisible)
(Show a) => -- how to make a String from one element (invisible)
[a] -> -- the list of elements to be told (visible)
String -- the String made by showing all the elements
Run Code Online (Sandbox Code Playgroud)
所以,当你使用时tell,例如,
tell [True, False]
Run Code Online (Sandbox Code Playgroud)
你只提供可见的参数:[True, False]要告诉的事项列表,编译器会找出不可见的参数.他知道True并且False都是类型的值Bool,所以这意味着
[True, False] :: [Bool]
Run Code Online (Sandbox Code Playgroud)
这是编译器如何计算出必须a在类型中制作的tellBool[a] = [Bool]
(顺便说一句,约[True, False] :: [Bool].左边的::方括号,[..],列表值.右边的::方括号,[..],列出一种类型.它们可能看起来像黑色在你的灰色背景上,但我的大脑将制作颜色的红色和制作颜色的颜色设为蓝色.它们完全不同.我希望我能在这个网站上为代码着色.我离题了.)
所以,现在,另一个看不见的论点必须满足这个(Show a)东西,我们现在知道这是特别的,(Show Bool)因为我们发现它a是Bool.我们将这部分类型称为"约束",但实际上它不仅要求事实是真的,而且存在一些有用的东西.这里要求的东西是有一个功能
show :: Bool -> String
Run Code Online (Sandbox Code Playgroud)
这是用来打开各个元素的功能True和False为StringS IN评估的过程tell [True, False].
所述标识符Show是一个的名称类型类和显示是该类型类的方法.类型class指定必须为每个操作实现的操作接口instance.函数的不可见参数是一个记录(或"字典")打包所讨论类型的操作的实现(这里,实现show).如果没有这些信息,编译后的代码将无法完成其工作,但我们不必编写该信息,因为编译器可以(至少在这种情况下)搜索它知道的实例并填写右侧一个人的工作.
因此,我们不仅具有不可见的类型参数(在编译时推断,然后在运行时删除),由小写类型变量发出信号,或者更明确地由forall blah表示 ..我们还有类型类操作的不可见实现(在编译时查找,以提供重要的运行时信息).因此,在推断和擦除类型之间发生了一些非常重要的事情:虽然编译器仍然知道类型,但它使用它们来确定在运行时需要哪些不可见的实现,这样我们就可以自己不编写它们.
缩小,=>在类型文档中我们期望编译器将使用类型信息来指导生成我们不必费心写入的运行时代码.那是一个很好的一点胜利,就在那里.
类型系统黑客的别有用心.隐形可见区别与可擦除有用区别不同的信息是某些人尚未收到的区别.这是典型的Hindley-Milner职位,但事实是这些区别是正交的,人们越早学会享受,就越好.
在=>首先介绍和解释第3章-类型和类型类:
==函数的类型签名是什么?
Run Code Online (Sandbox Code Playgroud)ghci> :t (==) (==) :: (Eq a) => a -> a -> Bool注意:等于运算符,==是一个函数.+,*, - ,/和几乎所有运营商都是如此.如果函数仅由特殊字符组成,则默认情况下它被视为中缀函数.如果我们想检查它的类型,将它传递给另一个函数或将其称为前缀函数,我们必须将它括在括号中.
有趣.我们在这里看到一个新的东西,=>符号.=>符号之前的所有内容都称为类约束.我们可以像这样读取前面的类型声明:相等函数接受任何两个相同类型的值并返回一个Bool.这两个值的类型必须是Eq类的成员(这是类约束).