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
从命令式循环中进行比较和其他操作。累加器是一个由局部变量 max
和 index
组成的元组。由于最后只需要索引,因此我们使用 snd
来获取该部分。请注意,我们也将输入表示为元组,以使其更易于使用。
我刚开始学习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
从命令式循环中进行比较和其他操作。累加器是一个由局部变量 max
和 index
组成的元组。由于最后只需要索引,因此我们使用 snd
来获取该部分。请注意,我们也将输入表示为元组,以使其更易于使用。