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

1 haskell if-statement case

"Guards vs. If-Then-Else"帮助了一点,但我仍然想知道这是否可以以某种方式起作用.我需要获取一个列表并返回列表中的每个其他元素.对于偶数长度列表,我得到它只是如果长度(xs)mod2 == 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)
Run Code Online (Sandbox Code Playgroud)

它告诉我"if"可能存在"间距错误",但这在功能上是正确的.我可以这样做吗?

Dan*_*ner 5

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

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

总之,这些规则意味着模式01你的case陈述应相互对齐和缩进比第一更深eeveryOther.内部的表达应该更深,以避免混淆.这是满足这些约束的一种流行风格:

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)
Run Code Online (Sandbox Code Playgroud)

下一步:反引号(`- 通常位于键盘顶部数字行的左侧)和前向ticks(')表示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)
Run Code Online (Sandbox Code Playgroud)

接下来是概念错误.在类似的表达式中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)
Run Code Online (Sandbox Code Playgroud)

既然我们现在在两个分支中都有相同的代码case,那么很明显这不是你的意图; 但我不清楚你的意图什么.

还有一种可疑的(虽然再次,不是技术上的错误)详情:请记住,在fooeveryOther (x:xs) = foo,名单xs不包括给列表的第一个元素everyOther.因此length xs,与给定的输入长度相比,调用类似于一个调用everyOther.在为语句的模式01模式编写表达式时,请考虑到这一点case.

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

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