Haskell: Multiple Case Statements in Single Function

╄→尐↘猪︶ㄣ 提交于 2019-12-05 20:24:06

问题


I want to include more than one case statement in a Haskell function (see below for an example of a hypothetical function).

However, it is not legal Haskell. What is a better way of accomplishing the same thing? Furthermore, if the case statements are not returning anything, but simply setting some value, why is it not legal to have more than one case statement in a function?

(I would get a "parse error on input `case'" on line 5)

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." 

Note that if my function were simply:

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

...then it would compile.


回答1:


In general the body of a function has to be a single expression (very often made up of smaller expressions). The following isn't allowed, for example:

f x y =
  "foo"
  "bar"

This is equivalent to your first example—we've just substituted one kind of expression (string literals) for another (your case expressions).

It's certainly possible to include more than one case expression in a Haskell function:

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."

Or even:

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."

These work because the body of the function is a single expression (although neither is really idiomatic Haskell).




回答2:


I wouldn't use a case statement in this case though, this IMO looks better:

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." 



回答3:


In general, it looks like what you want is guards. However, as already mentioned, your function is not a single expression. Assuming that you want to return a tuple of strings, it can be written like this using guards (and some added fun from 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)

You could also drop the Control.Arrow bit all together and write:

tester x y = (testx x, testy y)


来源:https://stackoverflow.com/questions/4242002/haskell-multiple-case-statements-in-single-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!