views:

441

answers:

4

//edit 5 when the i use only these 2 lines

  index :: [String] -> [String] -> Bool
  index a b = and [x `elem` a |x <- b]

it works fine!!!!

eg:

index ["asd","asdd","dew"] ["asdd","asdad"]

False

But when i use the entire code mentioned below

empty [] = True
empty _ = False

    index a b = do
             if empty a
              then do putStrLn "a is empty"
                      else return ()
             if empty b
              then do putStrLn "b is empty"
                      else return ()
        where
          index :: [String] -> [String] -> Bool
          index a b = and [x `elem` a |x <- b]

theres no output!! and thats the issue i got!!

//edit 6

index a b = do index'
         if empty a
          then do putStrLn "a is empty"
                  else return ()
         if empty b
          then do putStrLn "b is empty"
                  else return ()
    where
      index' :: [String] -> [String] -> Bool
      index' a b = and [x `elem` a |x <- b]

thanks

A: 

IO operations in Haskell are a bit difficult because they need so called monads You would need a special do-notion here to sequence the outputs.

Write it like this:

empty [] = True
empty _ = False

index a b = do
         if empty a
          then do putStrLn "a is empty"
    else return ()
         if empty b
          then do putStrLn "b is empty"
    else return ()

Or Maybe you could just return the strings and use putStrLn separately. You index' must return a boolean value when it should be used as an if condition!

Dario
What's wrong with this?
Dario
thanks it worked fine!
pier
You won't need the `do` syntax here, if you remove all the `do`s, your code will still work.
Tom Lokhorst
The `empty` function here already exists in the Prelude, it's called `null` and it's defined in exactly the same way.
Tom Lokhorst
How would the code look without do? It makes two separate outputs so both conditions and `putStrLn`s must be sequenced monadically = do.
Dario
Oh, right, I didn't read your code properly. You are right, you need the outer `do`. Btw, there is also a function for `if b then something else return ()` called `when`. You can use it like so: `when (empty a) (putStrLn "a is empty")`. It is in the `Control.Monad` module.
Tom Lokhorst
Nice, thank you ;-)
Dario
index a b = when (empty a) (putStrLn "a is empty") when (empty b) (putStrLn "b is empty")why isn't this possible? index a b = when (empty a) (putStrLn "a is empty") worked fine!thanks
pier
You will need `do` notation to sequence the two calls to `when`.
Tom Lokhorst
many thanks! I learned alot.
pier
hmm 1 more thingafter 'do' why isnt it possible to define the index type likeempty [] = Trueempty _ = Falseindex a b = do if empty a then do putStrLn "a is empty" else return () if empty b then do putStrLn "b is empty" else return () where index :: [String] -> [String] -> Bool index a b = and [x `elem` a |x <- b]
pier
or like thisorimport Control.Monadempty [] = Trueempty _ = Falseindex a b = do when (empty a) (putStrLn "a is empty") when (empty b) (putStrLn "b is empty") where index :: [String] -> [String] -> Bool index a b = and [x `elem` a |x <- b]
pier
@dlna, could you update your question instead of posting comments? The comments are hard to read without indentation.
Tom Lokhorst
ok i updated the question.
pier
A: 
index a b = if index' [] bs
                       then putStrLn "a is empty"
                       if index' a []          
                        then putStrLn "b is empty"
                        else                  
    where 
        index' :: [String] -> [String] -> [Int]
        index' a b = index' True [(elem x b) | x <- a]

If you indent your statement like this you'll see that the first if has no matching else clause.

Also, else clause doesn't return anything — a function should have a return value under all circumstances.

apostlion
+2  A: 

An if construct in Haskell is a expression. That means it must always evaluate to a value, so the else part is mandatory.

Also, the first part of if must be a boolean, so you can't call index' there, since that returns a [Int], not a Bool.

I would say, start with something like this:

if isEmpty a
then putStrLn "a is empty"
else if isEmpty b
     then putStrLn "b is empty"
     else putStrLn "neither are empty"
Tom Lokhorst
ok, well i tried it this way and i still get an error as "Syntax error in expression (unexpected `}', possibly due to bad layout)"index as bs = if isEmpty as then putStrLn "a is empty" else if isEmpty bs then putStrLn "b is empty" else putStrLn "neither are empty" where index' :: [String] -> [String] -> [Int] index' as bs = index' True [(elem a bs) | a <- as]
pier
You'll need `do` to sequence the outputs.
Dario
Than you probably do have a problem with your layout. Make sure the `then` and `else` keywords are indented to at least the level of the `if` keyword. In your current question, the `else` is indented wrong. Also, make sure you only use spaces for layout, tabs will mess thing up.
Tom Lokhorst
@Dario, the you don't really need `do` syntax in this example. In this case, the expression will be of type `IO ()`, because `putStrLn` is of that type. `do` syntax is just syntax sugar if you want to bind multiple expressions, but that's not necessary here.
Tom Lokhorst
I'll have to bind multiple expressions - The programm may outputa is emptyb is empty
Dario
Right, my example will only output one string, because it is a nested `if`. Should you want to print out multiple strings, you would have to bind two expressions, then you could use the `do` notation.
Tom Lokhorst
+4  A: 

This is a little off-topic since maybe you are trying to learn the layout rule and how to nest ifs, but the code you show in revision 6 is just using if to do error checking. I would just do the error checking via pattern matching instead of if.

index [] _ = putStrLn "a is empty"
index _ [] = putStrLn "b is empty"
index a b = putStrLn (show index')
    where index' = and [x `elem` a | x <- b]

(You don't need the return () after putStrLn because it already returns () for you.)

Pattern matching is a lot easier to get right because it doesn't require a lot of indentation, etc.


Edit:

I changed the definition of index' a little from yours. In my version it's a local variable instead of a local function. In Haskell, there's not much difference, it's just that index' uses a and b from the surrounding index function, so it doesn't need to take parameters. (Admittedly, index' is not such a good name for a variable.)

Also I left off the type annotation because I don't usually write them. But they are helpful when something isn't working. Here is what it would look like:

    where index' :: Bool
          index' = and [x `elem` a | x <- b]
Nathan Sanders
short and doesn't have to worry about identation.thanks
pier
why dont i need to define the type likeindex' :: [String] -> [String] -> Bool
pier
The compiler generally can deduce the types automatically, so you don't need to declare them manually if you don't want to. But it's usually better to declare them because it helps to find the problematic code in case of type errors. In this case you could declare the type of index as "[String] -> [String] -> IO ()" or more generally as "(Eq a) => [a] -> [a] -> IO ()".
sth