9

Haskell 関数に複数の case ステートメントを含めたいと考えています (仮想関数の例については、以下を参照してください)。

ただし、合法的な Haskell ではありません。同じことを達成するためのより良い方法は何ですか? さらに、case ステートメントが何も返さず、単純に何らかの値を設定する場合、1 つの関数に複数の 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"

これは最初の例と同じです。ある種類の式(文字列リテラル)を別の種類の式(ケース式)に置き換えただけです。

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

一般的に、あなたが欲しいのは警備員のように見えます。ただし、すでに述べたように、関数は単一の式ではありません。文字列のタプルを返したいと仮定すると、ガードを使用して次のように書くことができます(そして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 に答える