Привет, я новичок в Haskell и всю свою жизнь использую более классические языки программирования. Понятия не имею, что здесь происходит. Я пытаюсь сделать очень простую реализацию алгоритма Витерби, но только для двух состояний (честное и нечестное казино)
У меня проблема, когда я хочу обратиться к своему массиву, но я не думаю, что правильно понимаю типы. Или я создаю новый массив каждый раз, когда пытаюсь обратиться к нему - так же глупо. Посмотрите, пожалуйста, на myArray, te infix и dynamicProgram. Довольно красиво, пожалуйста
Code
import Array
import Char
trans :: Int -> Int -> Double -> Double -> Double
trans from x trans11 trans21 =
if (from == 1) && (x == 1)
then trans11
else if (from == 1) && (x == 2)
then (1-trans11)
else if (from == 2) && (x == 1)
then trans21
else (1-trans21)
em :: Char -> [Double] -> Double
em c list = list!! a
where a = digitToInt c
intToChar :: Int -> Char
intToChar n | n == 1 = '1'
| n == 2 = '2'
casino :: Char -> Int -> Int -> [Double] -> [Double] -> Double -> Double -> Double
casino seqchar 1 y em1 em2 t1 t2= 0.5 * (em seqchar em1)
casino seqchar 2 y em1 em2 t1 t2= 0.5 * (em seqchar em2)
casino seqchar x y em1 em2 t1 t2= maximum[ (1 @@ y-1)*(em seqchar em1)*(trans 1 x t1 t2),(2 @@ y-1)*(em seqchar em2)*(trans 2 x t1 t2) ]
dynamicProgram :: [Char] -> (Char -> Int -> Int -> [Double] -> [Double] -> Double -> Double -> Double) -> [Double] -> [Double] -> Double -> Double -> (Array a b)
dynamicProgram string score list1 list2 trans11 trans21 = myArray 1 len
[score (string!!y) x y list1 list2 trans11 trans21 | x Int -> [Double] -> Array a b
myArray startIndex endIndex values = listArray (startIndex,startIndex) (endIndex,endIndex) values
traceback :: [Char] -> Int -> Int -> [Double] -> [Double] -> Double -> Double -> [Char]
traceback s 1 0 em1 em2 t1 t2 = []
traceback s 2 0 em1 em2 t1 t2 = []
traceback s x y em1 em2 t1 t2 | x@@y == (1 @@ y-1)*(em (s!!y) em1)*(trans 1 x t1 t2) = '1' : traceback s 1 (y-1) em1 em2 t1 t2
| x@@y == (2 @@ y-1)*(em (s!!y) em1)*(trans 2 x t1 t2) = '2' : traceback s 2 (y-1) em1 em2 t1 t2
answer :: [Char] -> [Double] -> [Double] -> Double -> Double -> [Char]
answer string list1 list2 t1 t2 = reverse $ maxC : traceback string max end list1 list2 t1 t2 $ dynamicProgram casino string list1 list2 t1 t2
where
end = (length string) + 1
max | maximum (1@@end) (2@@end) == 1@@end = 1
| maximum (1@@end) (2@@end) == 2@@end = 2
maxC = intToChar max
infix 5 @@
(@@) i j = myArray ! (i, j)
main = do
putStrLn "What is the sequence to test?"
seq state 1 transmission probability?"
trp1 state 2 transmission probability is " ++ (1-trp1)
putStrLn "What is the state 2 -> state 1 transmission probability?"
trp2 state 2 transmission probability is " ++ (1-trp2)
putStrLn "I assume that the prob of starting in either state is 1/2. Go!"
answer seq st1 st2 trp1 trp2





Я скопировал код из окна редактирования (что-то в парсере stackoverflow съедает часть кода) и попробовал его на ghci, который обнаружил несколько ошибок. Первая ошибка была:
foo.hs:34:71:
Couldn't match expected type `[e]' against inferred type `(a, b)'
In the second argument of `listArray', namely
`(endIndex, endIndex)'
In the expression:
listArray (startIndex, startIndex) (endIndex, endIndex) values
In the definition of `myArray':
myArray startIndex endIndex values
= listArray (startIndex, startIndex) (endIndex, endIndex) values
Тип listArray:
listArray :: (Ix i) => (i, i) -> [e] -> Array i e
-- Defined in GHC.Arr
Требуется кортеж с нижней и верхней границами и список. Итак, правильное выражение, вероятно, будет:
listArray (startIndex, endIndex) values
И тип myArray - это не Array a b, это Array Int Double.
Вторая ошибка была:
foo.hs:43:44:
Couldn't match expected type `a -> b'
against inferred type `[Char]'
In the first argument of `($)', namely
`maxC : (traceback string max end list1 list2 t1 t2)'
In the second argument of `($)', namely
`(maxC : (traceback string max end list1 list2 t1 t2))
$ (dynamicProgram casino string list1 list2 t1 t2)'
In the expression:
reverse
$ ((maxC : (traceback string max end list1 list2 t1 t2))
$ (dynamicProgram casino string list1 list2 t1 t2))
$ является правоассоциативным, поэтому сначала рассматривается крайний правый $. Первым параметром для него должна быть функция, которую он будет вызывать с самым правым параметром в качестве аргумента. Но вот список.
Третья ошибка:
foo.hs:51:11:
Couldn't match expected type `Array i e'
against inferred type `Int -> Int -> [Double] -> Array a b'
In the first argument of `(!)', namely `myArray'
In the expression: myArray ! (i, j)
In the definition of `@@': @@ i j = myArray ! (i, j)
myArray не является массивом; это функция, которая принимает три параметра и строит на их основе массив.
Здесь, вероятно, вас сбивает с толку то, что вы привыкли к более традиционным императивным языкам. В традиционном императивном языке было бы естественно иметь глобальную переменную myArray, к которой вы затем можете получить доступ из середины вашей программы. В Haskell, однако, отсутствуют более сложные уловки, которые вы не должны пробовать, пока вы новичок, «глобальная» переменная больше похожа на постоянное значение (которое лениво вычисляется при первом использовании, но которое, насколько вам интересно, могло быть вычислено компилятором при создании вашего исполняемого файла). Вы не можете инициализировать его из значений, которые считываете как входные.
Лучший способ обойти это - передать массив через программу, что, к сожалению, потребует нескольких изменений и сводит на нет полезность вашего оператора @@. Вы можете скрыть передачу массива несколькими более продвинутыми способами, но во время обучения лучше быть более явным.
Последняя ошибка была:
foo.hs:63:4:
Couldn't match expected type `[a]' against inferred type `IO ()'
In the first argument of `(++)', namely
`putStrLn
"I assume that the state 1 -> state 2 transmission probability is "'
In the expression:
(putStrLn
"I assume that the state 1 -> state 2 transmission probability is ")
++
(1 - trp1)
In a 'do' expression:
(putStrLn
"I assume that the state 1 -> state 2 transmission probability is ")
++
(1 - trp1)
Это имеет две ошибки: та, на которую пожаловался компилятор, является проблемой приоритета, как ясно показывают добавленные компилятором круглые скобки, и которую можно легко исправить путем правильного применения скобок или оператора $. Другая ошибка, которую вы обнаружите после исправления этой ошибки, заключается в том, что вы не можете объединить строку и число; вам нужно преобразовать число в строку.
И все это происходило без просмотра алгоритма или даже большей части кода, а просто с учетом ошибок компилятора. Например, если вам нужен двумерный массив, правильным выражением для первой ошибки будет:
listArray ((startIndex, startIndex), (endIndex, endIndex)) values
Теперь обе границы являются кортежами, а его тип - Array (Int, Int) Double.
Вы можете переписать транс-функцию так:
trans :: Int -> Int -> Double -> Double -> Double
trans 1 1 trans11 trans21 = trans11
trans 1 2 trans11 trans21 = 1-trans11
trans 2 1 trans11 trans21 = trans21
trans _ _ trans11 trans21 = 1-trans21