This code :
这段代码:
y :: Int
y = y + 1
When executed causes GHCI to hang.
执行时会导致GHCI挂起。
y :: Int; this means y is of type Int
y = y + 1; this means y is defined to be an Int + 1
Please correct me if I'm incorrect in definitions of statements.
如果我在陈述的定义上不正确,请纠正我。
Why does y not evaluate ?
你为什么不评价?
Is reason that y is being added to an Int, but its just being added to a type not to a value ?
是y被添加到Int的原因,但它只是被添加到一个类型而不是一个值?
3 个解决方案
#1
Speaking more broadly, a Haskell file (or GHCi) does NOT contain a list of imperatives/orders, like some other programming languages. It is a different style of programming language. Instead there are a handful of kinds of top-level statements which you have access to:
更广泛地说,Haskell文件(或GHCi)不包含命令/命令列表,就像其他一些编程语言一样。它是一种不同风格的编程语言。相反,您可以访问以下几种*语句:
-
You can define values.
y = y + 1
defines the symboly
to be an application of a function(+)
to two other parameters,y
and1
. This definition holds throughout the file, in particular to things above the definition and within the definition. So, you can totally writey = x + 1
and thenx = 2
in a.hs
file and ask GHCi fory
and it will say3
. Note that this gets more complicated with thelet
keyword, which forms a "wall" to this expansive nature of definition:let
accepts a block of definitions and a value-expression and scopes those definitions to within the combined (block-of-definitions, value-expression) context, but walls off those definitions from the world outside thelet
. So this is valid, too:您可以定义值。 y = y + 1将符号y定义为函数(+)对另外两个参数y和1的应用。该定义在整个文件中保存,特别是在定义之上和定义内。所以,你可以在.hs文件中完全写y = x + 1然后x = 2.并且向GHCi询问y并且它会说3.请注意,使用let关键字会变得更加复杂,这会形成一个“墙”定义的这种广泛性:接受一个定义块和一个值表达式,并将这些定义范围限定在组合(定义块,值表达式)上下文中,但是在let之外的世界中除去那些定义。所以这也是有效的:
Prelude> let y = x + 1; x = 2 Prelude> y 3
-
You can define data structures and their constructors. A constructor is a special function which we allow to participate in pattern-matching: in other words, Haskell knows how to invert or destructure every constructor. You can also define a
type
synonym and anewtype
, which is halfway in-between those.您可以定义数据结构及其构造函数。构造函数是一个特殊的函数,我们允许它参与模式匹配:换句话说,Haskell知道如何反转或解构每个构造函数。您还可以定义类型同义词和新类型,它们介于两者之间。
-
You can provide metadata about individual values (type declarations). These are really helpful for narrowing down where a type error is because they set up a "wall" for the type inference algorithm. They also can have semantic effects either in adding polymorphism (Haskell has a "monomorphism restriction" which often bites newcomers) or in restricting that polymorphism to a concrete type.
您可以提供有关各个值的元数据(类型声明)。这些对于缩小类型错误的位置非常有用,因为它们为类型推断算法设置了“墙”。它们还可以在添加多态性(Haskell具有经常咬新手的“单态限制”)或将该多态性限制为具体类型时具有语义效果。
-
You can provide metadata about the package as a whole: both how it incorporates other packages (import statements) and how it can be used by other packages (module statements).
您可以提供有关整个包的元数据:它如何包含其他包(import语句)以及其他包(模块语句)如何使用它。
None of these are orders that you're giving to the Haskell system; instead your file is all one big description of a module. Similarly within an expression (the first part above) there are only a couple of things you can do, and they are not usually imperatives: you can apply values to other values, create functions, you can create local definitions (let
) and pattern-match (case
), and you can locally add type metadata. Everything else, including do
notation, is just a more convenient way ("syntactic sugar") to do those things above.
这些都不是你给Haskell系统的命令;相反,你的文件是模块的一个大的描述。类似地,在表达式(上面的第一部分)中,您只能执行一些操作,并且它们通常不是必需的:您可以将值应用于其他值,创建函数,您可以创建本地定义(let)和模式 - 匹配(案例),您可以在本地添加类型元数据。其他所有内容,包括符号,都只是一种更方便的方法(“语法糖”)来完成上述事情。
Your two statements are a type declaration ("the type of the y
defined by this module will be an integer") and a definition ("to compute a y
as defined by this module, first compute the value of a y
, then add one to it"). Haskell reads both of them together and says, "oh, y
has type Int
, so (+)
is the specific Int-Plus operation that I know, (+) :: Int -> Int -> Int
, and then 1
is the specific Int
of that name which I know... . It will then confirm that the types are self-consistent and produce some imperative code which loops forever.
你的两个语句是一个类型声明(“这个模块定义的y的类型将是一个整数”)和一个定义(“按照这个模块的定义计算ay,首先计算ay的值,然后加一个“)。 Haskell一起读取它们并说:“哦,你有类型Int,所以(+)是我知道的特定Int-Plus操作,(+):: Int - > Int - > Int,然后1是我知道的那个名称的特定Int ...然后它将确认这些类型是自洽的,并产生一些永远循环的命令性代码。
#2
That's because it recurses infinitely. You are calling y
which is defined as y + 1
. So how will the evaluation proceed ?
那是因为它无限地递归。您正在调用y,其定义为y + 1.那么评估将如何进行?
It goes like this:
它是这样的:
y
y + 1
(y + 1) + 1
((y + 1) + 1) + 1
and so on...
等等...
#3
Haskell has no variables, only constants, thus, you cannot use the same style as in other languages, with updatable values referring to the last. It does mean, however, that you can do some pretty awesome things, which you've tripped upon.
Haskell没有变量,只有常量,因此,你不能使用与其他语言相同的样式,可更新的值指的是最后一个。然而,这确实意味着你可以做一些非常棒的事情,你已经绊倒了。
Take this declaration as an example:
以此声明为例:
myList = 1 : myList
When evaluated, this will refer to itself, thus doing this:
在评估时,这将引用自身,从而这样做:
myList = 1 : myList -- but I'm referring to myList, so...
myList = 1 : (1 : myList) -- but I'm referring to myList, so...
myList = 1 : (1 : (1 : myList)) -- but I'm referring to myList, so...
myList = 1 : 1 : 1 : 1 : 1 : 1... -- etc.
The same goes for your constant y
:
你的常数y也是如此:
y = y + 1 -- but I'm referring to y, so...
y = y + 1 + 1 -- but I'm referring to y, so...
y = y + 1 + 1 + 1 -- but I'm referring to y, so...
y = 1 + 1 + 1 + 1 ... -- etc.
GHCi can never completely evaluate the value of y
, because it's infinite, causing GHCi to hang.
GHCi永远无法完全评估y的值,因为它是无限的,导致GHCi挂起。
#1
Speaking more broadly, a Haskell file (or GHCi) does NOT contain a list of imperatives/orders, like some other programming languages. It is a different style of programming language. Instead there are a handful of kinds of top-level statements which you have access to:
更广泛地说,Haskell文件(或GHCi)不包含命令/命令列表,就像其他一些编程语言一样。它是一种不同风格的编程语言。相反,您可以访问以下几种*语句:
-
You can define values.
y = y + 1
defines the symboly
to be an application of a function(+)
to two other parameters,y
and1
. This definition holds throughout the file, in particular to things above the definition and within the definition. So, you can totally writey = x + 1
and thenx = 2
in a.hs
file and ask GHCi fory
and it will say3
. Note that this gets more complicated with thelet
keyword, which forms a "wall" to this expansive nature of definition:let
accepts a block of definitions and a value-expression and scopes those definitions to within the combined (block-of-definitions, value-expression) context, but walls off those definitions from the world outside thelet
. So this is valid, too:您可以定义值。 y = y + 1将符号y定义为函数(+)对另外两个参数y和1的应用。该定义在整个文件中保存,特别是在定义之上和定义内。所以,你可以在.hs文件中完全写y = x + 1然后x = 2.并且向GHCi询问y并且它会说3.请注意,使用let关键字会变得更加复杂,这会形成一个“墙”定义的这种广泛性:接受一个定义块和一个值表达式,并将这些定义范围限定在组合(定义块,值表达式)上下文中,但是在let之外的世界中除去那些定义。所以这也是有效的:
Prelude> let y = x + 1; x = 2 Prelude> y 3
-
You can define data structures and their constructors. A constructor is a special function which we allow to participate in pattern-matching: in other words, Haskell knows how to invert or destructure every constructor. You can also define a
type
synonym and anewtype
, which is halfway in-between those.您可以定义数据结构及其构造函数。构造函数是一个特殊的函数,我们允许它参与模式匹配:换句话说,Haskell知道如何反转或解构每个构造函数。您还可以定义类型同义词和新类型,它们介于两者之间。
-
You can provide metadata about individual values (type declarations). These are really helpful for narrowing down where a type error is because they set up a "wall" for the type inference algorithm. They also can have semantic effects either in adding polymorphism (Haskell has a "monomorphism restriction" which often bites newcomers) or in restricting that polymorphism to a concrete type.
您可以提供有关各个值的元数据(类型声明)。这些对于缩小类型错误的位置非常有用,因为它们为类型推断算法设置了“墙”。它们还可以在添加多态性(Haskell具有经常咬新手的“单态限制”)或将该多态性限制为具体类型时具有语义效果。
-
You can provide metadata about the package as a whole: both how it incorporates other packages (import statements) and how it can be used by other packages (module statements).
您可以提供有关整个包的元数据:它如何包含其他包(import语句)以及其他包(模块语句)如何使用它。
None of these are orders that you're giving to the Haskell system; instead your file is all one big description of a module. Similarly within an expression (the first part above) there are only a couple of things you can do, and they are not usually imperatives: you can apply values to other values, create functions, you can create local definitions (let
) and pattern-match (case
), and you can locally add type metadata. Everything else, including do
notation, is just a more convenient way ("syntactic sugar") to do those things above.
这些都不是你给Haskell系统的命令;相反,你的文件是模块的一个大的描述。类似地,在表达式(上面的第一部分)中,您只能执行一些操作,并且它们通常不是必需的:您可以将值应用于其他值,创建函数,您可以创建本地定义(let)和模式 - 匹配(案例),您可以在本地添加类型元数据。其他所有内容,包括符号,都只是一种更方便的方法(“语法糖”)来完成上述事情。
Your two statements are a type declaration ("the type of the y
defined by this module will be an integer") and a definition ("to compute a y
as defined by this module, first compute the value of a y
, then add one to it"). Haskell reads both of them together and says, "oh, y
has type Int
, so (+)
is the specific Int-Plus operation that I know, (+) :: Int -> Int -> Int
, and then 1
is the specific Int
of that name which I know... . It will then confirm that the types are self-consistent and produce some imperative code which loops forever.
你的两个语句是一个类型声明(“这个模块定义的y的类型将是一个整数”)和一个定义(“按照这个模块的定义计算ay,首先计算ay的值,然后加一个“)。 Haskell一起读取它们并说:“哦,你有类型Int,所以(+)是我知道的特定Int-Plus操作,(+):: Int - > Int - > Int,然后1是我知道的那个名称的特定Int ...然后它将确认这些类型是自洽的,并产生一些永远循环的命令性代码。
#2
That's because it recurses infinitely. You are calling y
which is defined as y + 1
. So how will the evaluation proceed ?
那是因为它无限地递归。您正在调用y,其定义为y + 1.那么评估将如何进行?
It goes like this:
它是这样的:
y
y + 1
(y + 1) + 1
((y + 1) + 1) + 1
and so on...
等等...
#3
Haskell has no variables, only constants, thus, you cannot use the same style as in other languages, with updatable values referring to the last. It does mean, however, that you can do some pretty awesome things, which you've tripped upon.
Haskell没有变量,只有常量,因此,你不能使用与其他语言相同的样式,可更新的值指的是最后一个。然而,这确实意味着你可以做一些非常棒的事情,你已经绊倒了。
Take this declaration as an example:
以此声明为例:
myList = 1 : myList
When evaluated, this will refer to itself, thus doing this:
在评估时,这将引用自身,从而这样做:
myList = 1 : myList -- but I'm referring to myList, so...
myList = 1 : (1 : myList) -- but I'm referring to myList, so...
myList = 1 : (1 : (1 : myList)) -- but I'm referring to myList, so...
myList = 1 : 1 : 1 : 1 : 1 : 1... -- etc.
The same goes for your constant y
:
你的常数y也是如此:
y = y + 1 -- but I'm referring to y, so...
y = y + 1 + 1 -- but I'm referring to y, so...
y = y + 1 + 1 + 1 -- but I'm referring to y, so...
y = 1 + 1 + 1 + 1 ... -- etc.
GHCi can never completely evaluate the value of y
, because it's infinite, causing GHCi to hang.
GHCi永远无法完全评估y的值,因为它是无限的,导致GHCi挂起。