0
votes

I'm making a stack based pseudo-assembler virtual machine. Here are some custom types used in the problem function:

type Program = Array Int Opcode
type Labels = Map String Int
type Stack = [Integer]
type Memory = Map String Integer
type VarList = [(String, Integer)]

Here's the problem function; there are about 20 other cases, but I'm only going to put the 3 that seem relevant to this problem:

runFrom :: Int -> Program -> VarList -> String
runFrom i p vars = step i [] (fromList vars) [] where
  labels = labelMap p
  step i stack mem out =
    case ((Array.!) p i, stack) of
      (CALL name, s) -> step ((Map.!) labels name) ((i+1):s) mem out
      (INT n, s)     -> step (i+1) (n:s) mem out
      (J name, s)    -> step ((Map.!) labels name) s mem out

First of all, the problem is the "CALL" case; the other two cases work fine when "CALL" is commented out. For the sake of clarity, "INT Integer" pushes an Integer onto the stack, and "J String" unconditionally jumps to the instruction that is mapped to the String name. "CALL String" is supposed to push onto the stack the index of the next instruction (i+1) and unconditionally jump to the label name. However, if I try to load the code above, GHC complains about not being able to match the expected Integer type against the inferred Int type in second argument of step for the "INT" case. Since "INT" works fine when "CALL" is commented out, I assume something screwy is going on in CALL (perhaps the ((i+1):s) ?). Can someone help me fix CALL?

2
The definition of Opcode may matter.user395760
@delnan Opcode is just the datatype for the assembler function, i.e.: data Opcode = CALL String | INT Integer | J String deriving (Eq, Show)user977680
Perhaps it is because type Labels = Map String Int so labels map to Int whereas Stack, Memory, and VarList use integers. CALL forces the first argument of step to be an Int which is at odds with the use of Int and J.vivian
@vivian You called it! "(CALL name, s) -> step ((Map.!) labels name) (fromIntegral(i+1):s) mem out" seems to have fixed it. Thanks.user977680
By the way, the (Array.!) p i and (Map.!) labels name syntax is beyond weird. Why not use infix functions the way they were meant to be used, e.g. as p Array.! i and labels Map.! name?Daniel Wagner

2 Answers

6
votes

Your Ints and Integers are inconsistent... If there's some specific reason you need to use both in different situations, and also to convert from one to the other, use fromIntegral as an explicit conversion. Otherwise just settle on one (probably Int).

3
votes

Because type Labels = Map String Int so labels map to Int whereas Stack, Memory, and VarList use Integers. CALL forces the first argument of step to be an Intwhich is at odds with the use of INT and J