Я использую функциональность линий, чтобы принять ввод и разделить множество переменных перед отправкой в функцию. Посмотрите на функцию запуска и скажите, почему я получаю следующую ошибку. Похоже, он должен просто присвоить 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


Я не уверен, правильно ли это, но проблема мощь заключается в том, что <- не является оператором присваивания, поскольку вы казаться его используете; по сути, он распаковывает значение из монады. Но я не совсем уверен, причина вашей проблемы в этом или нет.
Помните, что списки - это монады в 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)
Я думаю, что использование let в нотации do просто переводится как let ..... in do ..... я немного помню это
Я не думаю, что выражения действительно переводятся в какие-либо более примитивные формы (я могу ошибаться). Это просто базовая языковая конструкция. Я обновил свой пост, чтобы показать, что, по моему мнению, хотел OP.
Да, я думаю, что Мипади прав. нотация 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]. Я бы вам посоветовал поступить так:
добавьте тестовое значение, отформатированное как ожидаемый файл. Что-то типа:
t = "[1,9]\n3\n1.0 1.0 1.0\n1.0 1.0 1.0\n1.0\n1.0"
добавить тестовые значения, которые являются верхним уровнем для значений, которые вы определяете при запуске
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)
использовать подпись типа оценкаФункция, которая поможет вам в приводя аргументы в пользу этого функция, затем остальная часть выполнения и, наконец, main.
Научитесь пользоваться переводчиком, например Hugs, ghci. Изучите команды: r и: t. Например (я использую каррирование, чтобы передать некоторые, но не все аргументы функций):
:t scoreFunction
:t scoreFunction ""
:t scoreFunction 3445
Вы можете использовать это, чтобы система помогла вам определить, на правильном ли вы пути. Выполнение этого на верхнем уровне с вызовом конфликта с функцией Prelude.seq - либо переименуйте свой seq, либо укажите свой как Main.seq.
Haskell печально известен сообщениями об ошибках, которые непостижимы для новичков, поэтому я бы рекомендовал периодически возвращаться к компилируемой версии, либо комментируя ваши текущие эксперименты (это то, что я заставлял вас делать на шаге 1 выше), либо используя свой редакторы отменить функцию.
[1] Я говорю, вероятно, потому что строки, являющиеся списками символов, являются экземплярами класса Monad, но это довольно продвинутое
Спасибо, что освежили мою память тем, как do переводится в то, что хочет монада. Можете ли вы указать, как переводятся слова let? Думаю, это поможет ему и мне тоже :)