是否“<-"意味着在 Haskell 中分配一个变量? [英] Does "<-" mean assigning a variable in Haskell?

查看:27
本文介绍了是否“<-"意味着在 Haskell 中分配一个变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

刚开始使用Haskell,据说除了IO包外,Haskell中的所有内容都是不可变的".因此,当我将名称绑定到某物时,它总是不可变的?问题,如下所示:

前奏>让 removeLower x=[c|c<-x, c `elem` ['A'..'Z']]前奏>removeLower "aseruiiUIUIdkf"UIUI"

所以在这里:

1.removeLower"是不可变的?即使它是一个函数对象?但是我仍然可以使用let"来为这个名称分配其他东西.2.在函数c<-x"里面,似乎c"是一个变量.它由列表 x 的值分配.

我使用的是 C 语言中的变量"这个词,不知道 Haskell 是如何命名它的所有名称的?

谢谢.

解决方案

如果你熟悉 C,想想声明一个变量和赋值一个变量之间的区别对它的价值.例如,您可以自己声明一个变量,然后再分配给它:

int i;我 = 7;

或者你可以同时声明一个变量并赋值:

int i = 7;

在任何一种情况下,您都可以通过在第一次初始化或赋值后再次赋值来改变变量的值:

int i = 7;//声明和初始赋值我 = 5;//突变

Haskell 中的赋值完全像第二个例子——声明与初始化:

  1. 你声明了一个变量;
  2. Haskell 不允许使用未初始化的变量,因此您需要在声明中提供一个值;
  3. 没有变化,所以声明中给出的值将是该变量在其范围.

我加粗并超链接范围",因为它是这里的第二个关键组件.这是您的问题之一:

<块引用>

removeLower"是不可变的?即使它是一个函数对象?但我仍然可以使用let"为这个名称分配其他东西.

在您将 removeLower 绑定到您在示例中定义的函数后,名称 removeLower 将始终引用该函数在该定义的范围内.这很容易在解释器中演示.首先,让我们定义一个函数foo:

前奏>让 foo x = x + 2前奏>富 46

现在我们定义一个使用foobar:

前奏>让 bar x = foo (foo x)前奏>第 4 小节8

现在我们重新定义"foo 为不同的东西:

前奏>让 foo x = x + 3前奏>富 47

现在你认为 bar 会发生什么?

前奏>第 4 小节8

还是一样!因为 foo 的重新定义"不会改变任何东西——它只是说,在重新定义"创建的新作用域中,名称 foo 代表将三相加的函数.bar 的定义是在前面的作用域中定义的,其中 foo x = x + 2,所以这就是名称 foo 在那个范围内的含义bar 的定义.foo 的原始值没有被重新定义"破坏或改变.<​​/p>

在 Haskell 程序和 C 程序中一样,在程序的不同范围内,相同的名称仍然可以引用不同的值.这就是使变量"可变的原因.不同之处在于,在 Haskell 中,您永远不能在一个范围内改变变量的值.但是,您可以隐藏一个定义——变量的使用在某种意义上将引用该名称的最近"定义.(在解释器的情况下,该变量的最新 let 声明.)

<小时>

现在,除此之外,这里是 Haskell 中存在的用于变量绑定(赋值")的语法.首先,模块中有顶级声明:

module MyLibrary (addTwo) whereaddTwo :: Int ->整数加两个 x = x + 2

这里的名称 addTwo 是用给定的函数作为它的值声明的.顶级声明可以在 where 块中包含私有的辅助声明:

addSquares :: Integer ->整数addSquares x y = squareOfX + squareOfY其中正方形 z = z * zsquareOfX = 平方 xsquareOfY = 平方 y

然后是 let ... in ... 表达式,它允许您为任何表达式声明一个局部变量:

addSquares :: Integer ->整数加平方 x y =让平方 z = z * zsquareOfX = 平方 xsquareOfY = 平方 y在 squareOfX + squareOfY

然后是 do 符号,它有自己的语法来声明变量:

例子:: IO()例子=做putStrLn "请输入您的名字:"名字 <- getLineputStrLn "请输入您的姓氏:"姓氏 <- getLine让 fullName = firstName ++ " " ++ lastNameputStrLn(你好,"++全名++!")

var <- action 分配一个由 action 产生的值(例如,从标准输入中读取一行),而 let var =expr 分配一个由函数 产生的值(例如,连接一些字符串).请注意,do 块中的 let 与上面的 let ... in ... 不同!

最后,在列表推导中,您将获得与 do-notation 中相同的赋值语法.

Just started Haskell, it's said that everything in Haskell is "immutable" except IO package. So when I bind a name to something, it's always something immutable? Question, like below:

Prelude> let removeLower x=[c|c<-x, c `elem` ['A'..'Z']]
Prelude> removeLower "aseruiiUIUIdkf"
"UIUI"

So here:

1. "removeLower" is an immutable? Even it's a function object?
But I can still use "let" to assign something else to this name.

2. inside the function "c<-x" seems that "c" is a variable.
It is assigned by list x's values.

I'm using the word "variable" from C language, not sure how Haskell name all its names?

Thanks.

解决方案

If you're familiar with C, think of the distinction between declaring a variable and assigning a value to it. For example, you can declare a variable on its own and later assign to it:

int i;
i = 7;

Or you can declare a variable and assign initial value at the same time:

int i = 7;

And in either case, you can mutate the value of a variable by assigning to it once more after the first initialization or assignment:

int i = 7;  // Declaration and initial assignment
i = 5;      // Mutation

Assignment in Haskell works exclusively like the second example—declaration with initialization:

  1. You declare a variable;
  2. Haskell doesn't allow uninitialized variables, so you are required to supply a value in the declaration;
  3. There's no mutation, so the value given in the declaration will be the only value for that variable throughout its scope.

I bolded and hyperlinked "scope" because it's the second critical component here. This goes one of your questions:

"removeLower" is an immutable? Even it's a function object? But I can still use "let" to assign something else to this name.

After you bind removeLower to the function you define in your example, the name removeLower will always refer to that function within the scope of that definition. This is easy to demonstrate in the interpreter. First, let's define a function foo:

Prelude> let foo x = x + 2
Prelude> foo 4
6

Now we define an bar that uses foo:

Prelude> let bar x = foo (foo x)
Prelude> bar 4
8

And now we "redefine" foo to something different:

Prelude> let foo x = x + 3
Prelude> foo 4
7

Now what do you think happens to bar?

Prelude> bar 4
8

It remains the same! Because the "redefinition" of foo doesn't mutate anything—it just says that, in the new scope created by the "redefinition", the name foo stands for the function that adds three. The definition of bar was made in the earlier scope where foo x = x + 2, so that's the meaning that the name foo has in that definition of bar. The original value of foo was not destroyed or mutated by the "redefinition."

In a Haskell program as much as in a C program, the same name can still refer to different values in different scopes of the program. This is what makes "variables" variable. The difference is that in Haskell you can never mutate the value of a variable within one scope. You can shadow a definition, however—uses of a variable will refer to the "nearest" definition of that name in some sense. (In the case of the interpreter, the most recent let declaration for that variable.)


Now, with that out of the way, here are the syntaxes that exist in Haskell for variable binding ("assignment"). First, there's top-level declarations in a module:

module MyLibrary (addTwo) where

addTwo :: Int -> Int
addTwo x = x + 2

Here the name addTwo is declared with the given function as its value. A top level declaration can have private, auxiliary declarations in a where block:

addSquares :: Integer -> Integer
addSquares x y = squareOfX + squareOfY
  where square z = z * z
        squareOfX = square x
        squareOfY = square y

Then there's the let ... in ... expression, that allows you to declare a local variable for any expression:

addSquares :: Integer -> Integer
addSquares x y = 
  let square z = z * z
      squareOfX = square x
      squareOfY = square y
  in squareOfX + squareOfY

Then there's the do-notation that has its own syntax for declaring variables:

example :: IO ()
example = do
  putStrLn "Enter your first name:"
  firstName <- getLine

  putStrLn "Enter your lasst name:"
  lastName <- getLine

  let fullName = firstName ++ " " ++ lastName
  putStrLn ("Hello, " ++ fullName ++ "!")

The var <- action assigns a value that is produced by an action (e.g., reading a line from standard input), while let var = expr assigns a value that is produced by a function (e.g., concatenating some strings). Note that the let in a do block is not the same thing as the let ... in ... from above!

And finally, in list comprehension you get the same assignment syntax as in do-notation.

这篇关于是否“&lt;-"意味着在 Haskell 中分配一个变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆