Question

The following is my dining philosophers code and yields a compilation error saying "The last statement in a 'do' construct must be an expression: mVar2 <- newEmptyMVar mVar3" Can Somebody help me fix this error and get this program working? thank you

import Control.Concurrent
import Control.Concurrent.MVar
import System.Random

takefork :: Int -> forks -> IO ()
takefork n forks = takeMVar (forks!!n)

releasefork :: Int -> forks -> IO ()
releasefork n forks = putMVar (forks!!n)

philosopher :: [Int]
philosopher = [1,2,3,4,5]

forks :: [MVar] -> [Int]
forks = do
    takefork n ( philosopher - 1)
    threadDelay delay
    let delay = 100000
    takefork n philosopher
    putStrLn("Philosopher" ++ philosopher ++ "has started eating")
    releasefork n philosopher
    releasefork n ( philosopher - 1)
    ptStrLn ("Philosopher" ++ philosopher ++ "has stopped eating")
    forks

main :: IO ()
main = do
    mVar1 <- newEmptyMVar
    mVar2 <- newEmptyMVar
    mVar3 <- newEmptyMVar
    mVar4 <- newEmptyMVar
    mVar5 <- newEmptyMVar
    let mVar = [mVar1, mVar2, mVar3, mVar4, mVar5]
    sequence_ [ forkIO forks (mVar philosopher) ]
Was it helpful?

Solution

There are many problems with your code.

The error message you report indicates you are probably mixing spaces and tabs. Get rid of the tabs and use only spaces.


You are presumably writing this program in order to practice writing Haskell programs, not in order to run the program for fun and profit. So we don't want to simply give you a working Dining Philosophers implementation, we want to help you write your implementation.

I cannot tell from your code how you expect it to work.

I'm going to focus on the last line:

sequence_ [ forkIO forks (mVar philosopher) ]

sequence_ :: [IO a] -> IO () --- give sequence_ a list of i/o actions, and it (returns an i/o action that) performs each action in order. From the [...], it looks like you are trying to give it a list, but with only one element. This is probably not what you mean.

forkIO :: IO () -> IO ThreadID --- give forkIO an i/o action, and it (returns an i/o action that) starts that i/o action running in a new thread, giving you the id of that thread.

There are two problems here:

  • forks is a function, not an i/o action (it's not even a function that returns an i/o action, though you probably mean it to be)
  • you give forkIO a second argunment ((mVar philosopher)), but it only takes one argument

mVar philosopher itself doesn't make any sense: mVar :: [MVar a] (it's a list of MVars, and I haven't worked out what type the MVars are supposed to contain) but you treat it like a function, passing it philosopher as an argument.

At this point a lightbulb blinks on above my head. You wish to call forks with parameters mVar and philosopher?

sequence_ [ forkIO (forks mVar philosopher) ]

We're still sequencing a single action though. Perhaps you wish to call forks with each element of philosopher in turn?

sequence_ $ map (\n -> forkIO (forks mVar n)) philosopher

We can simplify this to

mapM_ (\n -> forkIO (forks mVar n)) philosopher

This doesn't match up with the type you given forks :: [MVar] -> [Int]. But that's probably wrong, so you'll want to fix that function next.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top