Список строк Haskell по строкам

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

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
В чем разница между методом "==" и equals()
В чем разница между методом "==" и equals()
Это один из наиболее часто задаваемых вопросов новичкам на собеседовании. Давайте обсудим его на примере.
Замена символа по определенному индексу в JavaScript
Замена символа по определенному индексу в JavaScript
В JavaScript существует несколько способов заменить символ в строке по определенному индексу.
2
0
1 882
5

Ответы 5

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

Помните, что списки - это монады в 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 или что-то в этом роде вместо нотации.

Редактировать:

Так что я думаю, что это то, что вы хотите, используя let вместо 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)

Спасибо, что освежили мою память тем, как do переводится в то, что хочет монада. Можете ли вы указать, как переводятся слова let? Думаю, это поможет ему и мне тоже :)

Johannes Schaub - litb 16.11.2008 06:03

Я думаю, что использование let в нотации do просто переводится как let ..... in do ..... я немного помню это

Johannes Schaub - litb 16.11.2008 06:14

Я не думаю, что выражения действительно переводятся в какие-либо более примитивные формы (я могу ошибаться). Это просто базовая языковая конструкция. Я обновил свой пост, чтобы показать, что, по моему мнению, хотел OP.

Alasdair 16.11.2008 06:15

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

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

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

Во-первых, давайте посмотрим, как это интерпретирует компилятор:

run :: String -> String

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

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

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

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

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

Здесь речь идет не о монаде 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)

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

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

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

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

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

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

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

Другие вопросы по теме