Haskell: множественные выражения в одной функции - PullRequest
9 голосов
/ 22 ноября 2010

Я хочу включить более одного оператора 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 ]

10 голосов
/ 22 ноября 2010

В общем случае тело функции должно быть одним выражением (очень часто состоит из более мелких выражений). Следующее запрещено, например:

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

3 голосов
/ 22 ноября 2010

Я бы не использовал оператор 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." 
2 голосов
/ 22 ноября 2010

В общем, похоже, что вы хотите охранники .Однако, как уже упоминалось, ваша функция не является одним выражением.Предполагая, что вы хотите вернуть кортеж строк, это можно написать так, используя охрану (и некоторые дополнительные забавы от Стрелки ):

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...