Hey, I'm really new to Haskell and have been using more classic programming languages my whole life. I have no idea what is going on here. I'm trying to make a very simple Viterbi algorithm implementation, but for only two states (honest and dishonest casino)
I have a problem where I want to address my array, but I don't think I'm getting types right. That or I'm making a new array each time I try to address it - equally stupid. Look at myArray, te infix, and dynamicProgram especially, PLEASE. Pretty pretty please
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
-
I copied the code from the edit window (something in stackoverflow's parser is eating part of the code) and tried it on ghci, which found several errors. The first error was:
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) valuesThe type of listArray is:
listArray :: (Ix i) => (i, i) -> [e] -> Array i e -- Defined in GHC.ArrIt takes a tuple with the lower and upper bounds and the list. So, the correct expression would probably be:
listArray (startIndex, endIndex) valuesAnd the type of myArray is not
Array a b, it isArray Int Double.The second error was:
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))$is right associative, so the rightmost$is looked at first. The first parameter to it must be a function, which it will call with its rightmost parameter as the argument. Here, however, it is a list.The third error was:
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)myArrayis not an array; it is a function which takes three parameters and constructs an array based on them.Here probably your being used to more traditional imperative languages is tripping you. In a traditional imperative language, it would be natural to have a global
myArrayvariable which you then can access from the middle of your program. In Haskell however, absent more advanced trickery which you should not try while you are a beginner, a "global" variable is more like a constant value (which is lazily computed on first use, but which as far as you care could have been computed by the compiler while generating your executable). You cannot initialize it from values you read as input.Your best way around that is to pass the array through the program, which unfortunately will need several changes and negates the usefulness of your
@@operator. You can hide the passing of the array in several more advanced ways, but while learning it is best to be more explicit.The last error was:
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)This has two errors: the one the compiler complained about is a precedence problem, as the compiler-added parenthesis readly show, and which can easily be fixed by correct application of either parenthesis or the
$operator. The other error, which you will find after you fix this one, is that you cannot concatenate a string and a number; you have to convert the number to a string.This was all without looking at the algorithm or even most of the code, just looking at the compiler errors. If you want a two-dimensional array, for instance, the correct expression for the first error would be:
listArray ((startIndex, startIndex), (endIndex, endIndex)) valuesNow both bounds are tuples, and its type is
Array (Int, Int) Double.Godeke : Very nicely done! -
Thank you a lot Cesar. Then again, I think I figured out how I misinterpreted functional programming.
Now I am just defining a score function that is recursive based on the value before, and define a base case. Then all I do is feed in the string to interpret and index = length, and it calculates the end state, from which I then traceback to the beginning. So yeah, I was just trapped in an imperative mindset
aka no more arrays!
-
You can rewrite the trans-function like this:
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
0 comments:
Post a Comment