9

我想在 Haskell 函数中包含多个 case 语句(请参阅下面的假设函数示例)。

但是,它不是合法的 Haskell。有什么更好的方法来完成同样的事情?此外,如果 case 语句没有返回任何内容,而只是设置了一些值,那么为什么在一个函数中有多个 case 语句是不合法的呢?

(我会在第 5 行收到“输入‘case’的解析错误”)

tester x y =  
   case (x < 0) of  
       True -> "less than zero."  
       False -> "greater than or equal to zero."  
   case (y == "foo")  
       True -> "the name is foo."  
       False -> "the name is not foo." 

请注意,如果我的功能很简单:

tester x y =  
   case (x < 0) of  
       True -> "less than zero."  
       False -> "greater than or equal to zero."

...然后它会编译。

4

3 回答 3

10

通常,函数的主体必须是单个表达式(通常由较小的表达式组成)。不允许出现以下情况,例如:

f x y =
  "foo"
  "bar"

这等效于您的第一个示例-我们刚刚将一种表达式(字符串文字)替换为另一种(您的 case 表达式)。

在 Haskell 函数中当然可以包含多个 case 表达式:

tester :: Int -> String -> (String, String)
tester x y = (a, b)
  where
    a = case (x < 0) of  
          True -> "less than zero."  
          False -> "greater than or equal to zero."  
    b = case (y == "foo") of
          True -> "the name is foo."  
          False -> "the name is not foo."

甚至:

tester :: Int -> String -> IO ()
tester x y = do
  putStrLn $ case (x < 0) of  
               True -> "less than zero."  
               False -> "greater than or equal to zero."  
  putStrLn $ case (y == "foo") of
               True -> "the name is foo."  
               False -> "the name is not foo."

这些工作是因为函数的主体是一个单一的表达式(尽管两者都不是真正地道的 Haskell)。

于 2010-11-22T03:53:08.927 回答
3

不过在这种情况下我不会使用 case 语句,这个 IMO 看起来更好:

tester :: Int -> String -> String
tester x y | x < 0     = "less than zero. " ++ expr
           | otherwise = "greater than or equal to zero. " ++ expr
    where expr = if y == "foo" then "the name is foo." else "the name is not foo." 
于 2010-11-22T10:27:40.817 回答
2

一般来说,看起来你想要的是guards。但是,如前所述,您的函数不是单个表达式。假设你想返回一个字符串元组,它可以用守卫这样写(还有一些来自Arrows的乐趣):

import Control.Arrow

testx x | x < 0      = "Less then zero."
        | otherwise  = "Greater then or equal to zero."

testy y | y == "foo" = "The name is foo."
        | otherwise  = "The name is not foo."

tester = curry (testx *** testy)

您也可以将 Control.Arrow 位放在一起并编写:

tester x y = (testx x, testy y)
于 2010-11-22T12:25:50.483 回答