Haskell 循环和局部变量

Haskell loop and local variable

我刚开始学习Haskell,我不明白如何在Haskell中编写这样一个程序,其中有循环和局部变量。谁能建议这样的程序如何看待 Haskell?怎么替换第二个循环,因为涉及到局部变量?

#include <iostream>
using namespace std;

int main() {

int n;
int a [100];
cin >> n;

for (int i = 0; i < n; i ++) {
    cin >> a[i];
}

int max = 0;
int index = -1;

for (int i = 0; i < n - 1; i ++) {
    if (a[i+1] - a[i] > max) {
        max = a[i+1] + a[i];
        index = i;
    }
}

cout << index << endl;

return 0;

}

我尝试在 Haskell 中编写代码:

module MyProgram where 

import Data.List
import Data.Ord

-- Getting a new modernized list

f :: Int a => [a] -> [a]
f x = zipWith (-) (tail x) (x)

现在我只需要 运行 遍历列表并找到最大元素并存储其索引。我了解如何在 C 和 Java 中执行此操作,并给出了上面的示例,我将如何实施,但在 Haskell 中,因为没有循环。需要递归吗?

我的主要困难在于我不明白Haskell中的设计可以用其中的循环变量代替我。我在网上找资料,但没找到我能看懂的东西。

首先,您想获得元素之间差异的列表。让我们看看你的尝试:

f x = zipWith (-) (tail x) x

现在如果我们使用递归,我们可以这样定义它:

findMax :: [Int] -> Int
findMax list = helper 0 -1 minusInfinity $ zipWith (-) (tail list) list
  where
    helper _            maxIndex _          []          = maxIndex
    helper currentIndex maxIndex currentMax (elem:list)
      | elem > currentMax = helper (currentIndex + 1) currentIndex elem list
      | otherwise = helper (currentIndex + 1) maxIndex currentMax list
    minusInfinity = minBound :: Int -- the smallest element possible

但不知何故,递归相当丑陋和冗长。让我们看看我们是否可以做得更好:

f 已经生成了正确的减法列表。

现在您想将每个元素与其索引相关联。在 Haskell 中,使用 zip:

可以使用元组 (Int, Int) 轻松完成组合信息
zip [0..] list = [(0, 1st element), (1, 2nd element), ..]

您要考虑的元素现在是元组的右侧部分,可通过 snd:

访问
snd (index, elem) == elem

使用函数maximumBy,我们现在得到:

g x = maximumBy (comparing snd) $ zip [0..] $ f x

maximumBy (comparing snd) 表示 "getting the maximum element by comparing the snd part of each tuple"。现在 returns 元组 (index, element) 其中 element 是最大的。要访问元组的第一个元素,我们可以使用:

fst (index, element) == index

所以整个函数可以写成:

f x = fst $ maximumBy (comparing snd) $ zip [0..] $ zipWith (-) (tail x) x

这比上面的递归公式更优雅。

这是另一种方法:

import Data.List

calc :: (Integral a) => [a] -> a
calc = snd . foldl (\(max,index) (x,y) -> if (y-x) > max then (y+x,index) else (max,index + 1) ) (0,-1) . helper

helper :: [a] -> [(a,a)]
helper x = zip (tail x) (init x)

helper 构建一个连续的元素对列表。然后,calc 从命令式循环中进行比较和其他操作。累加器是一个由局部变量 maxindex 组成的元组。由于最后只需要索引,因此我们使用 snd 来获取该部分。请注意,我们也将输入表示为元组,以使其更易于使用。

Demo