haskell 中的变量赋值

Variable assignment in haskell

我正在尝试编写一个接受字符串的辅助函数,如果该字符串有多个 space,它会将它变成一个字符串。这是代码:

getSpaces :: String -> String
getSpaces index = 
    if (length index) == 1 then index
    else
        if isInfixOf " " index then index = " "
        else index

当我尝试将我的模块加载到 GHCI 中时,出现错误:

Prelude> :l Utilities
[1 of 1] Compiling Utilities        ( Utilities.hs, interpreted )

Utilities.hs:55:42: error:
parse error on input ‘=’
Perhaps you need a 'let' in a 'do' block?
e.g. 'let x = 5' instead of 'x = 5'
   |
55 |        if isInfixOf " " index then index = " "
   |                                          ^
Failed, no modules loaded.

为什么我无法将索引重新分配给单个 space?

我找到了一个修复程序,而不是更改索引,我只是 returning 一个 space。

代替:

if isInfixOf " " index then index = " "

我做到了:

if isInfixOf " " index then " "

所以我只是 return space。

Why am I not able to reassign index to a single space?

因为在 Haskell 中您无法重新分配任何内容。事实上,你甚至从来没有 assign,你 declare(这是相关的,但不同)。即使在某些情况下,它可能看起来像您重新分配变量(例如在 do 块中,您不会重新分配,但是您 shadow 变量通过声明一个具有相同的新变量name,这又有点相关,但是在很多情况下我们会看到不同的行为,例如在循环中,我们不能在每次迭代时都隐藏变量)。

为了回答您的问题,您可能想要 return 一个带有一个 space 的字符串,我们可以这样写:

getSpaces index = if (length index) == 1 then index else
                                 if isInfixOf " " index then <b>" "</b> else index

但是尽管如此,这仍然相当不优雅,而且相当不安全,因为在无限 String 的情况下,这将开始循环:length 一直循环直到列表(的characters) 已经用完了,这可能永远不会发生。此外,即使它没有陷入无限循环,它仍然是不可取的,因为它在 O(n) 中运行(n 列表的长度)。所以对于长列表,这是低效的。

通常在 Haskell 中,使用 patternsguards 的组合来区分可能的值。您的案例可以映射到:

getSpaces :: String -> String
getSpaces st@[_] = st
getSpaces st | isInfixOf " " st = st
             | otherwise = " "

这仍然会循环,但是,如果列表有无限大小,sinze isInfixOf 会一直寻找 space,直到找到一个,或者 String 已用完.

因为 isPrefixOf 作为搜索模式,一个带有 一个 字符的字符串实际上意味着我们查看字符串是否包含 space,我们可以替换使用 elem 并查找字符 ' ':

getSpaces :: String -> String
getSpaces st@[_] = st
getSpaces st | elem ' ' st = st
             | otherwise = " "