简体   繁体   English

什么=>在类型签名中意味着什么?

[英]What does => mean in a type signature?

I just starting Learn you a Haskell , and I saw this used in an example without explanation: 我刚开始学习一个Haskell ,我在一个例子中看到了这个没有解释:

tell :: (Show a) => [a] -> String

What does this mean, in particular the => ? 这是什么意思,特别是=> I know it won't work if I substitute -> or delete it, but I don't really understand why. 我知道如果我替换->或删除它将无法工作,但我不明白为什么。

Here's another way of looking at it. 这是另一种看待它的方式。 Some of a function's arguments are invisible, others are visible. 某些函数的参数是不可见的,其他参数是可见的。 A type input -> output tells us that a visible input is expected as an argument. 类型input -> output告诉我们可以将可见input作为参数。 A type (Constraint) => output tells us that some invisible information is expected. 类型(Constraint) => output告诉我们预期会有一些不可见的信息。 They're not interchangeable, because the visible arguments must be written, and the invisible arguments must not be written. 它们不可互换,因为必须写入可见的参数,并且不能写入不可见的参数。 The invisible arguments are for the compiler to figure out for himself (well, he sounds like a himself to me), and he insists on puzzling them out: he refuses just to be told what they are! 隐形的论据是让编译器为自己弄清楚(好吧,他听起来像是对我而言),他坚持要把它们弄得一团糟:他拒绝被告知它们是什么!

Secretly, the full type of this tell example is 偷偷的,完整的类型如此tell例子是

tell :: forall (a :: *). (Show a) => [a] -> String

What I've done is to make clear where this a variable comes in and what kind of a thing it is. 我所做的就是要明确这个地方a变量进来,什么样的事情是。 You can also read this as a "deal": tell offers to work for all types a which satisfy the demand (Show a) . 您还可以阅读这是一个“交易”: tell报价为各类工作的a满足需求(Show a)

In order for a usage of tell to make sense, it needs three things. 为了使用tell有意义,它需要三件事。 Two of them are invisible and one is visible. 其中两个是看不见的,一个是可见的。 That is, when you use tell , you make the visibile argument explicit, and the compiler tries to fill in the invisible parts. 也就是说,当你使用tell ,你可以使visibile参数显式化,并且编译器会尝试填充不可见的部分。 Let's work through that type more slowly. 让我们更慢地完成这种类型的工作。

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

So, when you use tell , eg, 所以,当你使用tell ,例如,

tell [True, False]

you give only the visible argument: the list [True, False] of things to tell, and the compiler figures out the invisible arguments. 你只提供可见的参数:要告诉的事项的列表[True, False] ,编译器会找出不可见的参数。 He knows that True and False are both values of type Bool , so that means 他知道TrueFalse都是Bool类型的值,所以这意味着

[True, False] :: [Bool]

which is how the compiler figures out that the a in the type of tell must be Bool , making [a] = [Bool] 这是编译器如何计算出tell的类型中的a必须是Bool ,使[a] = [Bool]

(By the way, about [True, False] :: [Bool] . Left of ::, the square brackets, [..], make list values. Right of ::, the square brackets, [..], make a type of lists. They may just look black on a grey background to you, but my brain colours the value-making brackets red and the type-making brackets blue. They are entirely different. I wish I could colour code on this site. I digress.) (顺便说一下,关于[True, False] :: [Bool] 。左边的::方括号,[..],列表值。右边的::,方括号,[..],make一种类型的清单。它们可能只是在灰色的背景上看起来是黑色的,但是我的大脑将制作颜色的颜色设为红色,而制作颜色的颜色为蓝色。它们完全不同。我希望我能在这个网站上设置颜色代码。我离题了。)

So, now, the other invisible argument must satisfy this (Show a) thing, which we now know is specifically (Show Bool) because we figured out that a is Bool . 所以,现在,另一个看不见的论点必须满足这个(Show a)东西,我们现在知道它是具体的(Show Bool)因为我们发现aBool We call this part of the type a "constraint", but really it's a demand not just that a fact is true, but that some useful stuff exists. 我们将这部分类型称为“约束”,但实际上它不仅要求事实是真的,而且存在一些有用的东西。 The stuff that is being demanded here is that there is a function 这里要求的东西是有一个功能

show :: Bool -> String

That's the function used to turn the individual elements True and False into String s in the process of evaluating tell [True, False] . 这是用于在评估tell [True, False]的过程中将单个元素TrueFalse转换为String的函数。

The identifier Show is the name of a type class and show is the method of that type class. 标识符Show类型类的名称, show是该类型类的方法。 A type class specifies an interface of operations which must be implemented for each instance . 类型class指定必须为每个instance实现的操作接口。 The invisible argument to the function is a record (or "dictionary") packaging the implementations of those operations for the type in question (here, the implementation of show ). 函数的不可见参数是一个记录(或“字典”)打包所讨论类型的操作的实现(这里是show的实现)。 Without that information, the compiled code would have no way to do its job, but we don't have to write that information, because the compiler can (at least in this case) search through the instances it knows about and fill in the right one for the job. 如果没有这些信息,编译后的代码将无法完成其工作,但我们不必编写该信息,因为编译器可以(至少在这种情况下)搜索它知道的实例并填写右侧一个人的工作。

So, we don't just have invisible type arguments (which are inferred at compile time, then erased before run time), signalled by lowercase type variables, or more explicitly by forall blah . 因此,我们不仅具有不可见的类型参数(在编译时推断,然后在运行时删除),由小写类型变量发出信号,或者更明确地由forall blah发出信号. . We also have invisible implementations of type class operations (which are looked up at compile time, to provide vital run time information). 我们还有类型类操作的不可见实现(在编译时查找,以提供重要的运行时信息)。 So, something very important happens between inferring and erasing types : while the compiler still knows the types, it uses them to figure out which invisible implementations will be needed at run time, so that we can get away with not writing them ourselves. 因此, 在推断和擦除类型之间发生了一些非常重要的事情:虽然编译器仍然知道类型,但它使用它们来确定在运行时需要哪些不可见的实现,这样我们就可以自己不写它们。

Zooming out, => in a type documents our expectation that the compiler will make use of type information to guide the generation of run time code that we don't have to bother writing. 缩小, =>在类型文档中我们期望编译器将使用类型信息来指导生成我们不必费心写入的运行时代码。 That's a nice little bit of win, right there. 那是一个很好的一点胜利,就在那里。

Ulterior motive for type system hackers. 类型系统黑客的别有用心。 The message that the invisible-visible distinction is in a different place from the erasable-useful distinction is one that some people have not yet received. 隐形可见区别与可擦除有用区别不同的信息是某些人尚未收到的区别。 That is the classic Hindley-Milner position, but the fact is that these distinctions are orthogonal, and the sooner people learn to enjoy that, the better. 这是典型的Hindley-Milner职位,但事实是这些区别是正交的,人们越早学会享受,就越好。

The => is first introduced and explained in Chapter 3 - Types and Typeclasses : =>首先在第3章 - 类型和类型类中介绍和解释:

What's the type signature of the == function? ==函数的类型签名是什么?

 ghci> :t (==) (==) :: (Eq a) => a -> a -> Bool 

Note: the equality operator, == is a function. 注意:等于运算符,==是一个函数。 So are +, *, -, / and pretty much all operators. +,*, - ,/和几乎所有运营商都是如此。 If a function is comprised only of special characters, it's considered an infix function by default. 如果函数仅由特殊字符组成,则默认情况下它被视为中缀函数。 If we want to examine its type, pass it to another function or call it as a prefix function, we have to surround it in parentheses. 如果我们想检查它的类型,将它传递给另一个函数或将其称为前缀函数,我们必须将它括在括号中。

Interesting. 有趣。 We see a new thing here, the => symbol. 我们在这里看到一个新的东西,=>符号。 Everything before the => symbol is called a class constraint. =>符号之前的所有内容都称为类约束。 We can read the previous type declaration like this: the equality function takes any two values that are of the same type and returns a Bool. 我们可以像这样读取前面的类型声明:相等函数接受任何两个相同类型的值并返回一个Bool。 The type of those two values must be a member of the Eq class (this was the class constraint). 这两个值的类型必须是Eq类的成员(这是类约束)。

It's a constraint on the type, means a should be an instance of class Show . 这是该类型的约束,意味着a应该是类的实例Show

see for example here 例如, 在这里看到

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM