Список строк на Haskell через строки - PullRequest
2 голосов
/ 16 ноября 2008

Я использую функциональность линий, чтобы получить входные данные и разделить многие переменные перед отправкой их функции. Пожалуйста, посмотрите на функцию запуска и скажите мне, почему я получаю следующую ошибку. Кажется, что нужно просто присвоить первой строке в ln seq, но я получаю ошибку.

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...
<code>
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
</code>

Ответы [ 5 ]

5 голосов
/ 16 ноября 2008

Сначала давайте посмотрим, как его интерпретирует компилятор:

run :: String -> String

String на самом деле [Char].

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

Упрощение вещей много , блок do должен "работать" в Monad. Это означает, что он «возвращает» значение типа (Monad t) => t a. Поскольку эта функция возвращает [Char], блок do вернет [Char], то есть Monad равно [] (если вы прочитаете [a] как [] a, это будет более ясно). *

Копирование из другого ответа моего,

Значительно упрощая, в блоке do монады ввода / вывода каждая строка имеет вид:

  • Что-то, что возвращает значение типа "IO a"; значение типа "a" внутри него отбрасывается (поэтому часто "a" равно "()")
  • A <- выражение, которое делает то же самое, но вместо отбрасывания значения типа "a" дает ему имя слева от <- </li>
  • let, которая ничего не делает, кроме как присваивает имя значению

Здесь мы не на IO Монаде, а на [] Монаде. Таким образом, выражение справа от <- должно быть [a].

Итак, в первой строке блока do:

    ln <- lines s

Здесь тип [[Char]], а тип ln равен [Char].

На следующей строке:

    seq <- ln!!0

Здесь ln!!0 имеет тип Char, но, поскольку вы находитесь в монаде [], он ожидает какой-то список. Это то, что вызывает сообщение об ошибке компилятора.

Решение состоит в том, чтобы вместо использования do использовать простой блок let:

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)

Я не скомпилировал этот блок, но даже если с ним что-то не так, этого должно быть достаточно, чтобы вы снова пошли.

0 голосов
/ 16 ноября 2008

run имеет тип String -> String, поэтому вам, вероятно, не нужна нотация do [1]. Я бы посоветовал вам сделать это:

  1. закомментируйте все ниже Функция listDouble, загрузите это, и будьте уверены, что скомпилируете.
  2. добавить тестовое значение, отформатированное так, как вы ожидаете. Что-то вроде:

     t = "[1,9]\n3\n1.0 1.0 1.0\n1.0 1.0 1.0\n1.0\n1.0"  
    
  3. добавить тестовые значения верхнего уровня для значений, которые вы определяете в прогоне

    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. использовать сигнатуру типа ScoreFunction, чтобы помочь вам в аргументы к этому функции, затем остаток выполнения и, наконец, основной.

Научитесь пользоваться переводчиком, таким как Hugs, GHCI. Изучите команды: r и: t. Например (я использую карри для получения некоторых, но не всех аргументов функций):

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

Вы можете использовать это, чтобы система помогла вам определить, находитесь ли вы на правильном пути. Делая это на верхнем уровне, вводите конфликт с функцией Prelude.seq - либо переименуйте ваш seq, либо сделайте ссылку на ваш как Main.seq.

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

[1] Я говорю, вероятно, потому что строки, являющиеся списками символов, являются экземплярами класса Monad, но это довольно продвинутое

0 голосов
/ 16 ноября 2008

Помните, что списки - это монады в haskell с определением:

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

Итак, если вы берете свой код, который выглядит примерно так:

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

Это эквивалентно следующему с использованием нотации связывания:

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

или более кратко:

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

Теперь мы можем использовать определение монады списка, чтобы переписать это следующим образом:

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

Что эквивалентно:

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

строки "hello, world" вернутся ["hello, world"], поэтому отображение (!! 0) на него приведет к строке "h". Это имеет тип [Char], но для concat требуется тип [[t]]. Char не соответствует [t], следовательно, ошибка.

Попробуйте использовать let или что-то, а не делать запись.

Edit:

Так что я думаю, это то, что вы хотите, используя пусть, а не делать.

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)
0 голосов
/ 16 ноября 2008

Да, я думаю, что Мипади прав. нотация do преобразуется в >> = и возвращает вызов монаде списка.

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

Получит список, возвращаемый lines s, а для seq и состояний ln будет строкой этого списка каждый раз. Так что на самом деле с ln !! 0 вы получите первый символ этой строки. Но список необходим справа от <- там. Это почти все, что я помню. Прошло совсем немного времени с тех пор, как я сделал это с помощью haskell:)

0 голосов
/ 16 ноября 2008

Я не уверен, что это правильно, но проблема может заключается в том, что <- не является оператором присваивания, так как вы , кажется, используете Это; это по существу распаковывает значение из монады. Но я не совсем уверен, является ли это причиной вашей проблемы или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...