views:

1008

answers:

5

Hey, I'm using the lines functionality to take an input and split up many variables before sending it off to a function. Please look at the run function and tell me why I get the following error. It seems like it should just assign the first string in ln to seq, but I get an error.

ERROR:dishonest.hs:33:11:
    Couldn't match expected type `[t]' against inferred type `Char'
    In a 'do' expression: seq <- ln !! 0
    In the expression:
        do ln <- lines s
           seq <- ln !! 0
           states <- ln !! 1
           l1 <- listDouble (ln !! 2)
           ....
    In the definition of `run':
        run s = do ln <- lines s
                   seq <- ln !! 0
                   states <- ln !! 1
                   ....
code follows...

import Char

maximumInd :: (Double, Double) -> Int
maximumInd (d1,d2) | maximum [d1,d2] == d1 = 1
                   | maximum [d1,d2] == d2 = 2

scoreFunction :: String -> Int -> [Double] -> [Double] -> Double -> Double -> (Double,Double)
scoreFunction string (-1) l1 l2 t1 t2 = (0.5, 0.5)
scoreFunction string index l1 l2 t1 t2 = ((fst (scoreFunction string (index-1) l1 l2 t1 t2)) * (l1!!num) * (tr (maximumInd (scoreFunction string (index-1) l1 l2 t1 t2))!!1), (snd (scoreFunction string (index-1) l1 l2 t1 t2)) * (l2!!num) * (tr (maximumInd (scoreFunction string (index-1) l1 l2 t1 t2))!!2))
    where
        num = digitToInt (string!!index)
        tr n | n == 1 = l1
             | n == 2 = l2

--split is stolen from teh webs http://julipedia.blogspot.com/2006/08/split-function-in-haskell.html
split :: String -> Char -> [String]
split [] delim = [""]
split (c:cs) delim
   | c == delim = "" : rest
   | otherwise = (c : head rest) : tail rest
   where
       rest = split cs delim

readDouble :: String -> Double
readDouble s = read s :: Double

listDouble :: String -> [Double]
listDouble s = map readDouble $ split s ' '

run :: String -> String
run s = do
    ln <- lines s
    seq <- ln!!0
    states <- ln!!1
    l1 <- listDouble (ln!!2)
    l2 <- listDouble (ln!!3)
    tr1 <- readDouble (ln!!4)
    tr2 <- readDouble (ln!!5)
    show maximumInd (scoreFunction seq (length seq) l1 l2 tr1 tr2)

main = do
    putStrLn "Please compose a test job for Viterbi."
    putStrLn "First line: A sequence with language [1,9]."
    putStrLn "Second line: The number of states."
    putStrLn "For the next 2 lines: space delimited emission probabilities."
    putStrLn "For the 2 lines after that, transmission probabilities."
    putStrLn "Then do ./casino < filename "
    interact run
A: 

I'm not sure if this is right, but the issue might lay in the fact that <- isn't an assignment operator, as you seem to be using it; it essentially unpacks a value from a monad. But I'm not really sure if that's the cause of your issue or not.

mipadi
A: 

Remember that lists are monads in haskell, with the definition:

instance Monad [] where
    m >>= f  = concatMap f m
    return x = [x]
    fail s   = []

So if you take your code, which goes something like:

do {ln <- lines "hello, world"; ln!!0}

That is equivalent to the following using bind notation:

lines "hello world" >>= (\ln -> ln!!0)

or more concisely:

lines "hello world" >>= (!!0)

We can now use the definition of the list monad to re-write that as the following:

concatMap (!!0) (lines "hello, world")

Which is equivalent to:

concat $ map (!!0) (lines "hello, world")

lines "hello, world" will return ["hello, world"], so mapping (!!0) over it will produce the string "h". That has type [Char], but concat requires a type [[t]]. Char does not match [t], hence the error.

Try using a let or something rather than do notation.

Edit:

So I think this is what you want, using let rather than do.

run :: String -> String
run s = let ln = lines s
            seq = ln!!0
            states = ln!!1
            l1 = listDouble (ln!!2)
            l2 = listDouble (ln!!3)
            tr1 = readDouble (ln!!4)
            tr2 = readDouble (ln!!5)
        in show $ maximumInd (scoreFunction seq (length seq) l1 l2 tr1 tr2)
Alasdair
Thanks for refreshing my memory with how do translates into what the monad wants. Can you maybe point out how the let stuff translates too? I think that will help him and me too :)
Johannes Schaub - litb
Tho i think using let in a do notation just translates to let ..... in do .... . i slightly remember that
Johannes Schaub - litb
I don't think let expressions actually translate down to any more primitive forms (I may be wrong), It's just a basic language construct. I updated my post to show what I think the OP wanted.
Alasdair
ah yeah i think youre right. he didnt want to use do at all
Johannes Schaub - litb
A: 

Yeah i think mipadi is right. the do notation translates into >>= and return calls to the list monad.

run s = do
    ln <- lines s
    seq <- ln!!0
    states <- ln!!1

Will get the list that is returned by lines s and for the seq and states, ln will be a string of that list each time. So actually with ln!!0, you get the first character of that string. But a list is required at the right side of the <- there. That's just about all what i remember. Has been quite a bit of time since i did those stuff with haskell :)

Johannes Schaub - litb
+4  A: 

First, let's look at how the compiler is interpreting it:

run :: String -> String

String is in fact [Char].

run s = do
    ln <- lines s
    ...

Simplifying things a lot, a do block must "run" in a Monad. This means that it "returns" a value of type (Monad t) => t a. Since this function is returning [Char], the do block will return [Char], meaning the Monad is [] (if you read [a] as [] a, it will be more clear).

Copying from another answer of mine,

Simplifying things a lot, on a do block on the IO monad, every line is either:

  • Something which returns a value of the "IO a" type; the value of the "a" type within it is discarded (so the "a" is often "()")
  • A <- expression, which does the same thing but instead of discarding the value of the "a" type gives it the name to the left of the <-
  • A let, which does nothing more than give a name to a value

Here we are not on the IO Monad, but on the [] Monad. So the expression to the right of the <- must be a [a].

So, in the first line of the do block:

    ln <- lines s

Here the type is [[Char]], and so the type of ln is [Char].

On the next line:

    seq <- ln!!0

Here ln!!0 has type Char, but since you are in the [] Monad, it is expecting a list of some sort. This is what causes the compiler's error message.

The solution is to, instead of using the do notation, use a plain let block:

run :: String -> String
run s = let
        ln = lines s
        seq = ln!!0
        states = ln!!1
        l1 = listDouble (ln!!2)
        l2 = listDouble (ln!!3)
        tr1 = readDouble (ln!!4)
        tr2 = readDouble (ln!!5)
    in show maximumInd (scoreFunction seq (length seq) l1 l2 tr1 tr2)

I did not compile this block, but even if there is something else wrong with it, it should be enough to get you going again.

CesarB
A: 

run is of type String -> String, so you probably don't want the do notation[1]. I'd advise you to do this:

  1. comment out everything below the listDouble function, load that, and be sure that'll compile.
  2. add a test value that's formatted like the file you expect. Something like:

     t = "[1,9]\n3\n1.0 1.0 1.0\n1.0 1.0 1.0\n1.0\n1.0"
    
  3. add a test values that the top level for the values you're defining in run

    ln = lines t
    seq = ln!!0
    states = ln!!1
    l1 = listDouble (ln!!2)
    l2 = listDouble (ln!!3)
    tr1 = readDouble (ln!!4)
    tr2 = readDouble (ln!!5)
    
  4. use the type signature of scoreFunction to guide you in building the arguments to that function, then the rest of run, and finally main.

Learn to use an interpreter, such as Hugs, ghci. Learn the :r and :t commands. For example (i'm using currying to give some but not all of a functions arguments):

  :t scoreFunction
  :t scoreFunction ""
  :t scoreFunction 3445

You can use this to have the system help you determine if you're on the right track. Doing this at the top level with introduce a conflict with a Prelude.seq function - either rename your seq, or refernence yours as Main.seq.

Haskell is notorious for error messages that are inscrutable to beginners, so I'd recommend periodically rolling back to a version that compiles, either by commenting out your current experiments (which is what I had you do in step 1 above), or using your editors undo function.

[1]I say probably because Strings, being lists of Characters, are instances of the Monad class, but that's fairly advanced

ja