“< - ”是否意味着在Haskell中分配变量?

时间:2016-02-04 10:43:46

标签: variables haskell immutability assign

刚开始使用Haskell,据说Haskell中的所有内容都是“不可变的”,除了IO包。所以,当我将某个名字绑定到某个东西时,它总是不可变的东西?问题,如下所示:

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

所以这里:

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.

我正在使用C语言中的“变量”这个词,不确定Haskell如何命名它的所有名称?

感谢。

3 个答案:

答案 0 :(得分:4)

如果您熟悉C,请考虑声明变量和为其分配值之间的区别。例如,您可以自己声明一个变量,然后分配给它:

int i;
i = 7;

或者您可以声明变量并同时指定初始值:

int i = 7;

在任何一种情况下,您都可以通过在第一次初始化或分配后再次分配变量值来变异

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

Haskell中的赋值完全像第二个带初始化的example-declaration:

  1. 您声明了一个变量;
  2. Haskell不允许未初始化的变量,因此您需要在声明中提供值;
  3. 没有变异,因此声明中给出的值将是整个scope中该变量的唯一值。
  4. 我加粗并超链接“范围”,因为它是这里的第二个关键组件。这是你的一个问题:

      

    “removeLower”是一个不可变的吗?即使它是一个函数对象?但是我仍然可以使用“let”为这个名字指定别的东西。

    removeLower绑定到您在示例中定义的函数后,名称removeLower将始终引用该定义范围内的函数。这很容易在口译员中证明。首先,让我们定义一个函数foo

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

    现在我们定义一个使用bar的{​​{1}}:

    foo

    现在我们将Prelude> let bar x = foo (foo x) Prelude> bar 4 8 重新定义为不同的东西:

    foo

    您认为Prelude> let foo x = x + 3 Prelude> foo 4 7 会发生什么?

    bar

    它仍然是一样的!因为Prelude> bar 4 8 的“重新定义”不会突变任何东西 - 它只是在“重新定义”创建的新范围中表示,名称{ {1}}代表增加三个的功能。 foo的定义是在foo的早期范围内进行的,因此bar的定义中foo x = x + 2名称的含义就是foobar的原始值未被“重新定义”破坏或变异。

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

    现在,除此之外,以下是Haskell中存在的用于变量绑定(“赋值”)的语法。首先,模块中有顶级声明:

    let

    这里使用给定函数声明名称module MyLibrary (addTwo) where addTwo :: Int -> Int addTwo x = x + 2 作为其值。顶级声明可以在addTwo块中包含私有辅助声明:

    where

    然后是addSquares :: Integer -> Integer addSquares x y = squareOfX + squareOfY where square z = z * z squareOfX = square x squareOfY = square y 表达式,允许您为任何表达式声明局部变量:

    let ... in ...

    然后是addSquares :: Integer -> Integer addSquares x y = let square z = z * z squareOfX = square x squareOfY = square y in squareOfX + squareOfY - 符号,它有自己的语法来声明变量:

    do

    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 ++ "!") 指定由操作生成的值(例如,从标准输入读取一行),而var <- action指定由a生成的值 function (例如,连接一些字符串)。请注意,let var = expr块中的let与上面的do不同!

    最后,在列表理解中,您将获得与let ... in ...中相同的赋值语法 - 符号。

答案 1 :(得分:3)

它指的是monadic绑定运算符>>=。您只需要将lambda显式写为右侧参数即可。列表comprension将被编译为定义的monadic动作。而且它意味着与monadic环境完全相同。

事实上,您可以通过简单调用filter来替换列表符号:

filter (`elem` ['A' .. 'Z']) x

回答关于<-句法结构的问题更清楚一点:

[c| c <- x]

相同
do c <- x
   return c

相同
x >>= \c -> return c

相同
x >>= return

考虑Haskell的官方文档以供进一步阅读:https://hackage.haskell.org/package/base-4.8.2.0/docs/Control-Monad.html#v:-62--62--61-

答案 2 :(得分:2)

[c|c<-x, c `elem` ['A'..'Z']]

list comprehensionc <- x是一个生成器,其中c是要从列表x的元素匹配的模式。 c是一种模式,它连续绑定到输入列表x的元素aseu, ...评估removeLower "aseruiiUIUIdkf"时。

c `elem` ['A'..'Z']

是一个谓词,它应用于理解中c的每个连续绑定,输入元素只有在传递此谓词时才出现在输出列表中。