Haskell: несколько операторов Case в одной функции
Я хочу включить более одного оператора case в функцию Haskell (см. ниже пример гипотетической функции).
однако это не является законным Haskell. Что может быть лучше для достижения того же самого? Кроме того, если операторы case ничего не возвращают, а просто устанавливают некоторое значение, почему не законно иметь более одного оператора case в функции?
(Я бы получил "ошибку разбора на входе "case "" в строке 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."
обратите внимание, что если бы моя функция была просто:
tester x y =
case (x < 0) of
True -> "less than zero."
False -> "greater than or equal to zero."
...затем он скомпилируется.
3 ответов
В общем тело функции должно быть одно выражение (очень часто состоит из меньших выражений). Например, не допускается следующее:
f x y =
"foo"
"bar"
Это эквивалентно вашему первому примеру-мы просто заменили один вид выражения (строковые литералы) на другой (ваши выражения case).
конечно, можно включить более одного выражения case в функцию Haskell:
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).
Я бы не использовал оператор 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."
В общем, похоже, что вы хотите гвардии. Однако, как уже упоминалось, ваша функция не является одним выражением. Предполагая, что вы хотите вернуть кортеж строк, его можно написать так, используя guards (и некоторые добавленные удовольствия от стрелки):
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)
вы также можете отказаться от управления.Стрелочка кусает все вместе и пишет:
tester x y = (testx x, testy y)