我对 Haskell 很陌生,而且对如何实现 for 循环也很困惑,因为我知道我们需要对它们使用递归。
例如,我有一个列表
[1,2,2,4,1]
,想要编写一个函数将每个2
更改为3
。我该怎么做呢?在Java中,我知道我会写以下内容
public void replace_two(List<Integer> ints) {
int i = 0;
for (int x: ints) {
if (x == 2) {
ints.set(i, 3);
}
i++;
}
System.out.println(ints);
}
但我不确定如何用 Haskell 重现类似的东西?
Haskell 中没有一个可以替代
for
循环的方法。更换具体取决于您想要做什么。在这种情况下,合适的是 map
:
replace_two = map go
where
go 2 = 3
go x = x
它的工作原理如下:
Prelude> replace_two [1,2,2,4,1]
[1,3,3,4,1]
Prelude>
Haskell 使用不同方法的组合来“排序”数据循环,例如列表。
有帮助的两件重要事情是:
例如,我在 haskell 中声明一个函数,如果输入为 3,则返回 2,否则返回输入。
return2 x = if x == 3 then 2 else x
现在我们想将此函数应用于列表的每个元素。所以我们将使用模式匹配。
apply (x:xs) = return2 x : apply xs
apply [] = []
这里模式
x:xs
将打破列表并获取 x
中的第一个元素,而 xs
将拥有列表的其余部分。在函数内部,您可以看到我们递归地应用了它。
我没有在IDE中检查上面的代码,所以它可能有语法错误,还有其他你需要验证的东西(列表末尾,在上面的代码中该函数会导致异常)。
上面的模式很常见,所以核心库中有另一个函数可以做到这一点,叫做map。所以你可以这样做:
map return2 [your list]
正如我所说,在 haskell 中,有很多方法可以本质上循环遍历事物,但从根本上讲,它们分解为将函数应用于数据结构中的各个项目。在它之上构建了许多 haskell 函数,例如 map、fold 等。
我建议您使用在线资源之一来更加熟悉 Haskell 结构。我喜欢并且很容易理解的一个是 Learn you a Haskell
使用模式和递归的另一种基本方法。
replace :: [Int] -> [Int]
replace [] = [] -- base case
replace (2:x) = 3:replace(x) --if 2 then replace by 3
replace (y:x) = y:replace(x) -- do nothing
除了
map
,也许你可以使用forM
中的Control.Monad
来模仿其他命令式语言中的for
循环:
import Control.Monad
arr = [1, 2, 2, 4, 1]
forM arr $ \i ->
if i == 2 then return 3 else return i
但是,您需要了解什么是
Monad
。