如何在Haskell的case语句中使用if / then / else或guards?

时间:2018-04-10 00:08:07

标签: haskell if-statement case

"后卫与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)

它告诉我可能存在"间距错误"在"如果"但这在功能上是否正确。我可以这样做吗?

1 个答案:

答案 0 :(得分:5)

此代码中似乎存在一些不同的错误,从语法到概念到算法的整个范围都有所不同。让我们从语法错误开始,然后向上移动。

Haskell中的代码被组织成块。块的每个元素必须以相同的缩进级别开始;对于初学者,嵌套块应使用比其周围块更深的缩进级别。在顶层,模块是一个块,其元素是方程式。 case / of也会开始一个块,其元素为pattern -> expression匹配。

这些规则一起表示0语句中的模式1case应该相互对齐,并且比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语句的01模式的表达式时,请考虑到这一点。

回到你的意图:因为你在两种模式中编写case,我认为你有时需要对该表达式进行评估。这让我觉得你有一个算法错误; everyOther (take 1 xs)几乎会丢弃所有输入列表,这与我对您希望take 1 xs做什么的理解不符。

希望此讨论可以指导您改进尝试,并且可以在实现目标方面取得更多进展。

相关问题