"后卫与If-Then-Else"帮助了一点,但我仍然想知道这是否可以以某种方式起作用。我需要获取一个列表并返回列表中的每个其他元素。对于偶数长度列表,我得到它只是如果长度(xs)mod
2 == 1开始是有问题所以我想打破列表情况的初始长度,如下所示:
everyOther:: [Int] -> [Int]
everyOther [] = []
everyOther (x:xs) = case length (xs) 'mod' 2 of 0 ->
if (length (xs) `mod` 2 == 0)
then x:everyOther (take 1 xs)
else x:everyOther (drop 1 xs)
1 -> if (length (xs) `mod` 2 == 1)
then x:everyOther (take 1 xs)
else x:everyOther (drop 1 xs)
它告诉我可能存在"间距错误"在"如果"但这在功能上是否正确。我可以这样做吗?
答案 0 :(得分:5)
此代码中似乎存在一些不同的错误,从语法到概念到算法的整个范围都有所不同。让我们从语法错误开始,然后向上移动。
Haskell中的代码被组织成块。块的每个元素必须以相同的缩进级别开始;对于初学者,嵌套块应使用比其周围块更深的缩进级别。在顶层,模块是一个块,其元素是方程式。 case
/ of
也会开始一个块,其元素为pattern -> expression
匹配。
这些规则一起表示0
语句中的模式1
和case
应该相互对齐,并且比e
everyOther
更深。 1}}。内部的表达应该更深,以避免混淆。这是满足这些约束的一种流行风格:
everyOther (x:xs) = case length (xs) 'mod' 2 of
0 -> if (length (xs) `mod` 2 == 0)
then x:everyOther (take 1 xs)
else x:everyOther (drop 1 xs)
1 -> if (length (xs) `mod` 2 == 1)
then x:everyOther (take 1 xs)
else x:everyOther (drop 1 xs)
下一步:反引号(`
- 通常位于键盘顶部数字行的左侧)和前向标记('
)表示Haskell中的不同内容。使用反引号将前缀函数转换为中缀函数非常重要;因此length (xs) 'mod' 2
应为length (xs) `mod` 2
。你还有很多冗余的括号,特别是围绕你length
的论证以及if
表达式的编码。虽然不是错误,但是学习优先级规则是值得的,因为您需要理解不会乱扔乱码的代码。
everyOther (x:xs) = case length xs `mod` 2 of
0 -> if length xs `mod` 2 == 0
then x:everyOther (take 1 xs)
else x:everyOther (drop 1 xs)
1 -> if length xs `mod` 2 == 1
then x:everyOther (take 1 xs)
else x:everyOther (drop 1 xs)
接下来是概念错误。在case foo of 0 -> a; 1 -> b
之类的表达式中,我们只会在a
时评估表达式foo == 0
,并且只会在b
时评估表达式foo == 1
。这使得您的条件下的测试变得多余;在case
的两个分支中,我们肯定会选择then
分支。因此,如果我们从字面上理解这个代码,那么将更简单,相当于编写它:
everyOther (x:xs) = case length xs `mod` 2 of
0 -> x:everyOther (take 1 xs)
1 -> x:everyOther (take 1 xs)
因为我们现在在case
的两个分支中都有相同的代码,所以很明显这不是你的意图;但我不清楚你的意图是。
还有另一个可疑的(虽然在技术上不是错误的)细节:请记住,在foo
的{{1}}中,列表everyOther (x:xs) = foo
会不包括给予xs
的列表的第一个元素。因此,与everyOther
的输入长度相比,length xs
之类的调用会被一个调用。在编写everyOther
语句的0
和1
模式的表达式时,请考虑到这一点。
回到你的意图:因为你在两种模式中编写case
,我认为你有时需要对该表达式进行评估。这让我觉得你有一个算法错误; everyOther (take 1 xs)
几乎会丢弃所有输入列表,这与我对您希望take 1 xs
做什么的理解不符。
希望此讨论可以指导您改进尝试,并且可以在实现目标方面取得更多进展。